home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume21 / berkeley_yacc / part04 < prev    next >
Encoding:
Internet Message Format  |  1990-04-05  |  57.0 KB

  1. Subject:  v21i081:  Public domain Berkeley YACC, Part04/05
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 6aa3eecf 099d47f4 b3954733 4f38ac5a
  5.  
  6. Submitted-by: Robert Corbett <corbett@ernie.berkeley.edu>
  7. Posting-number: Volume 21, Issue 81
  8. Archive-name: berkeley_yacc/part04
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 4 (of 5)."
  17. # Contents:  reader.c test/ftp.y
  18. # Wrapped by rsalz@litchi.bbn.com on Mon Apr  2 11:43:44 1990
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'reader.c' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'reader.c'\"
  22. else
  23. echo shar: Extracting \"'reader.c'\" \(30471 characters\)
  24. sed "s/^X//" >'reader.c' <<'END_OF_FILE'
  25. X#include "defs.h"
  26. X
  27. X/*  The line size must be a positive integer.  One hundred was chosen    */
  28. X/*  because few lines in Yacc input grammars exceed 100 characters.    */
  29. X/*  Note that if a line exceeds LINESIZE characters, the line buffer    */
  30. X/*  will be expanded to accomodate it.                    */
  31. X
  32. X#define LINESIZE 100
  33. X
  34. Xchar *cache;
  35. Xint cinc, cache_size;
  36. X
  37. Xint ntags, tagmax;
  38. Xchar **tag_table;
  39. X
  40. Xchar saw_eof, unionized;
  41. Xchar *cptr, *line;
  42. Xint linesize;
  43. X
  44. Xbucket *goal;
  45. Xint prec;
  46. Xint gensym;
  47. Xchar last_was_action;
  48. X
  49. Xint maxitems;
  50. Xbucket **pitem;
  51. X
  52. Xint maxrules;
  53. Xbucket **plhs;
  54. X
  55. Xint name_pool_size;
  56. Xchar *name_pool;
  57. X
  58. Xchar line_format[] = "#line %d \"%s\"\n";
  59. X
  60. X
  61. Xcachec(c)
  62. Xint c;
  63. X{
  64. X    assert(cinc >= 0);
  65. X    if (cinc >= cache_size)
  66. X    {
  67. X    cache_size += 256;
  68. X    cache = REALLOC(cache, cache_size);
  69. X    if (cache == 0) no_space();
  70. X    }
  71. X    cache[cinc] = c;
  72. X    ++cinc;
  73. X}
  74. X
  75. X
  76. Xget_line()
  77. X{
  78. X    register FILE *f = input_file;
  79. X    register int c;
  80. X    register int i;
  81. X
  82. X    if (saw_eof || (c = getc(f)) == EOF)
  83. X    {
  84. X    if (line) { FREE(line); line = 0; }
  85. X    cptr = 0;
  86. X    saw_eof = 1;
  87. X    return;
  88. X    }
  89. X
  90. X    if (line == 0 || linesize != (LINESIZE + 1))
  91. X    {
  92. X    if (line) FREE(line);
  93. X    linesize = LINESIZE + 1;
  94. X    line = MALLOC(linesize);
  95. X    if (line == 0) no_space();
  96. X    }
  97. X
  98. X    i = 0;
  99. X    ++lineno;
  100. X    for (;;)
  101. X    {
  102. X    line[i]  =  c;
  103. X    if (c == '\n') { cptr = line; return; }
  104. X    if (++i >= linesize)
  105. X    {
  106. X        linesize += LINESIZE;
  107. X        line = REALLOC(line, linesize);
  108. X        if (line ==  0) no_space();
  109. X    }
  110. X    c = getc(f);
  111. X    if (c ==  EOF)
  112. X    {
  113. X        line[i] = '\n';
  114. X        saw_eof = 1;
  115. X        cptr = line;
  116. X        return;
  117. X    }
  118. X    }
  119. X}
  120. X
  121. X
  122. Xchar *
  123. Xdup_line()
  124. X{
  125. X    register char *p, *s, *t;
  126. X
  127. X    if (line == 0) return (0);
  128. X    s = line;
  129. X    while (*s != '\n') ++s;
  130. X    p = MALLOC(s - line + 1);
  131. X    if (p == 0) no_space();
  132. X
  133. X    s = line;
  134. X    t = p;
  135. X    while ((*t++ = *s++) != '\n') continue;
  136. X    return (p);
  137. X}
  138. X
  139. X
  140. Xskip_comment()
  141. X{
  142. X    register char *s;
  143. X
  144. X    int st_lineno = lineno;
  145. X    char *st_line = dup_line();
  146. X    char *st_cptr = st_line + (cptr - line);
  147. X
  148. X    s = cptr + 2;
  149. X    for (;;)
  150. X    {
  151. X    if (*s == '*' && s[1] == '/')
  152. X    {
  153. X        cptr = s + 2;
  154. X        FREE(st_line);
  155. X        return;
  156. X    }
  157. X    if (*s == '\n')
  158. X    {
  159. X        get_line();
  160. X        if (line == 0)
  161. X        unterminated_comment(st_lineno, st_line, st_cptr);
  162. X        s = cptr;
  163. X    }
  164. X    else
  165. X        ++s;
  166. X    }
  167. X}
  168. X
  169. X
  170. Xint
  171. Xnextc()
  172. X{
  173. X    register char *s;
  174. X
  175. X    if (line == 0)
  176. X    {
  177. X    get_line();
  178. X    if (line == 0)
  179. X        return (EOF);
  180. X    }
  181. X
  182. X    s = cptr;
  183. X    for (;;)
  184. X    {
  185. X    switch (*s)
  186. X    {
  187. X    case '\n':
  188. X        get_line();
  189. X        if (line == 0) return (EOF);
  190. X        s = cptr;
  191. X        break;
  192. X
  193. X    case ' ':
  194. X    case '\t':
  195. X    case '\f':
  196. X    case '\r':
  197. X    case '\v':
  198. X    case ',':
  199. X    case ';':
  200. X        ++s;
  201. X        break;
  202. X
  203. X    case '\\':
  204. X        cptr = s;
  205. X        return ('%');
  206. X
  207. X    case '/':
  208. X        if (s[1] == '*')
  209. X        {
  210. X        cptr = s;
  211. X        skip_comment();
  212. X        s = cptr;
  213. X        break;
  214. X        }
  215. X        else if (s[1] == '/')
  216. X        {
  217. X        get_line();
  218. X        if (line == 0) return (EOF);
  219. X        s = cptr;
  220. X        break;
  221. X        }
  222. X        /* fall through */
  223. X
  224. X    default:
  225. X        cptr = s;
  226. X        return (*s);
  227. X    }
  228. X    }
  229. X}
  230. X
  231. X
  232. Xint
  233. Xkeyword()
  234. X{
  235. X    register int c;
  236. X    char *t_cptr = cptr;
  237. X
  238. X    c = *++cptr;
  239. X    if (isalpha(c))
  240. X    {
  241. X    cinc = 0;
  242. X    for (;;)
  243. X    {
  244. X        if (isalpha(c))
  245. X        {
  246. X        if (isupper(c)) c = tolower(c);
  247. X        cachec(c);
  248. X        }
  249. X        else if (isdigit(c) || c == '_' || c == '.' || c == '$')
  250. X        cachec(c);
  251. X        else
  252. X        break;
  253. X        c = *++cptr;
  254. X    }
  255. X    cachec(NUL);
  256. X
  257. X    if (strcmp(cache, "token") == 0 || strcmp(cache, "term") == 0)
  258. X        return (TOKEN);
  259. X    if (strcmp(cache, "type") == 0)
  260. X        return (TYPE);
  261. X    if (strcmp(cache, "left") == 0)
  262. X        return (LEFT);
  263. X    if (strcmp(cache, "right") == 0)
  264. X        return (RIGHT);
  265. X    if (strcmp(cache, "nonassoc") == 0 || strcmp(cache, "binary") == 0)
  266. X        return (NONASSOC);
  267. X    if (strcmp(cache, "start") == 0)
  268. X        return (START);
  269. X    if (strcmp(cache, "union") == 0)
  270. X        return (UNION);
  271. X    if (strcmp(cache, "ident") == 0)
  272. X        return (IDENT);
  273. X    }
  274. X    else
  275. X    {
  276. X    ++cptr;
  277. X    if (c == '{')
  278. X        return (TEXT);
  279. X    if (c == '%' || c == '\\')
  280. X        return (MARK);
  281. X    if (c == '<')
  282. X        return (LEFT);
  283. X    if (c == '>')
  284. X        return (RIGHT);
  285. X    if (c == '0')
  286. X        return (TOKEN);
  287. X    if (c == '2')
  288. X        return (NONASSOC);
  289. X    }
  290. X    syntax_error(lineno, line, t_cptr);
  291. X    /*NOTREACHED*/
  292. X}
  293. X
  294. X
  295. Xcopy_ident()
  296. X{
  297. X    register int c;
  298. X    register FILE *f = output_file;
  299. X
  300. X    c = nextc();
  301. X    if (c == EOF) unexpected_EOF();
  302. X    if (c != '"') syntax_error(lineno, line, cptr);
  303. X    ++outline;
  304. X    fprintf(f, "#ident \"");
  305. X    for (;;)
  306. X    {
  307. X    c = *++cptr;
  308. X    if (c == '\n')
  309. X    {
  310. X        fprintf(f, "\"\n");
  311. X        return;
  312. X    }
  313. X    putc(c, f);
  314. X    if (c == '"')
  315. X    {
  316. X        putc('\n', f);
  317. X        ++cptr;
  318. X        return;
  319. X    }
  320. X    }
  321. X}
  322. X
  323. X
  324. Xcopy_text()
  325. X{
  326. X    register int c;
  327. X    int quote;
  328. X    register FILE *f = text_file;
  329. X    int need_newline = 0;
  330. X    int t_lineno = lineno;
  331. X    char *t_line = dup_line();
  332. X    char *t_cptr = t_line + (cptr - line - 2);
  333. X
  334. X    if (*cptr == '\n')
  335. X    {
  336. X    get_line();
  337. X    if (line == 0)
  338. X        unterminated_text(t_lineno, t_line, t_cptr);
  339. X    }
  340. X    if (!lflag) fprintf(f, line_format, lineno, input_file_name);
  341. X
  342. Xloop:
  343. X    c = *cptr++;
  344. X    switch (c)
  345. X    {
  346. X    case '\n':
  347. X    next_line:
  348. X    putc('\n', f);
  349. X    need_newline = 0;
  350. X    get_line();
  351. X    if (line) goto loop;
  352. X    unterminated_text(t_lineno, t_line, t_cptr);
  353. X
  354. X    case '\'':
  355. X    case '"':
  356. X    {
  357. X        int s_lineno = lineno;
  358. X        char *s_line = dup_line();
  359. X        char *s_cptr = s_line + (cptr - line - 1);
  360. X
  361. X        quote = c;
  362. X        putc(c, f);
  363. X        for (;;)
  364. X        {
  365. X        c = *cptr++;
  366. X        putc(c, f);
  367. X        if (c == quote)
  368. X        {
  369. X            need_newline = 1;
  370. X            FREE(s_line);
  371. X            goto loop;
  372. X        }
  373. X        if (c == '\n')
  374. X            unterminated_string(s_lineno, s_line, s_cptr);
  375. X        if (c == '\\')
  376. X        {
  377. X            c = *cptr++;
  378. X            putc(c, f);
  379. X            if (c == '\n')
  380. X            {
  381. X            get_line();
  382. X            if (line == 0)
  383. X                unterminated_string(s_lineno, s_line, s_cptr);
  384. X            }
  385. X        }
  386. X        }
  387. X    }
  388. X
  389. X    case '/':
  390. X    putc(c, f);
  391. X    need_newline = 1;
  392. X    c = *cptr;
  393. X    if (c == '/')
  394. X    {
  395. X        putc('*', f);
  396. X        while ((c = *++cptr) != '\n')
  397. X        {
  398. X        if (c == '*' && cptr[1] == '/')
  399. X            fprintf(f, "* ");
  400. X        else
  401. X            putc(c, f);
  402. X        }
  403. X        fprintf(f, "*/");
  404. X        goto next_line;
  405. X    }
  406. X    if (c == '*')
  407. X    {
  408. X        int c_lineno = lineno;
  409. X        char *c_line = dup_line();
  410. X        char *c_cptr = c_line + (cptr - line - 1);
  411. X
  412. X        putc('*', f);
  413. X        ++cptr;
  414. X        for (;;)
  415. X        {
  416. X        c = *cptr++;
  417. X        putc(c, f);
  418. X        if (c == '*' && *cptr == '/')
  419. X        {
  420. X            putc('/', f);
  421. X            ++cptr;
  422. X            FREE(c_line);
  423. X            goto loop;
  424. X        }
  425. X        if (c == '\n')
  426. X        {
  427. X            get_line();
  428. X            if (line == 0)
  429. X            unterminated_comment(c_lineno, c_line, c_cptr);
  430. X        }
  431. X        }
  432. X    }
  433. X    putc('/', f);
  434. X    need_newline = 1;
  435. X    goto loop;
  436. X
  437. X    case '%':
  438. X    case '\\':
  439. X    if (*cptr == '}')
  440. X    {
  441. X        if (need_newline) putc('\n', f);
  442. X        ++cptr;
  443. X        FREE(t_line);
  444. X        return;
  445. X    }
  446. X    /* fall through */
  447. X
  448. X    default:
  449. X    putc(c, f);
  450. X    need_newline = 1;
  451. X    goto loop;
  452. X    }
  453. X}
  454. X
  455. X
  456. Xcopy_union()
  457. X{
  458. X    register int c;
  459. X    int quote;
  460. X    int depth;
  461. X    int u_lineno = lineno;
  462. X    char *u_line = dup_line();
  463. X    char *u_cptr = u_line + (cptr - line - 6);
  464. X
  465. X    if (unionized) over_unionized(cptr - 6);
  466. X    unionized = 1;
  467. X
  468. X    if (!lflag)
  469. X    fprintf(text_file, line_format, lineno, input_file_name);
  470. X
  471. X    fprintf(text_file, "typedef union");
  472. X    if (dflag) fprintf(union_file, "typedef union");
  473. X
  474. X    depth = 0;
  475. Xloop:
  476. X    c = *cptr++;
  477. X    putc(c, text_file);
  478. X    if (dflag) putc(c, union_file);
  479. X    switch (c)
  480. X    {
  481. X    case '\n':
  482. X    next_line:
  483. X    get_line();
  484. X    if (line == 0) unterminated_union(u_lineno, u_line, u_cptr);
  485. X    goto loop;
  486. X
  487. X    case '{':
  488. X    ++depth;
  489. X    goto loop;
  490. X
  491. X    case '}':
  492. X    if (--depth == 0)
  493. X    {
  494. X        fprintf(text_file, " YYSTYPE;\n");
  495. X        FREE(u_line);
  496. X        return;
  497. X    }
  498. X    goto loop;
  499. X
  500. X    case '\'':
  501. X    case '"':
  502. X    {
  503. X        int s_lineno = lineno;
  504. X        char *s_line = dup_line();
  505. X        char *s_cptr = s_line + (cptr - line - 1);
  506. X
  507. X        quote = c;
  508. X        for (;;)
  509. X        {
  510. X        c = *cptr++;
  511. X        putc(c, text_file);
  512. X        if (dflag) putc(c, union_file);
  513. X        if (c == quote)
  514. X        {
  515. X            FREE(s_line);
  516. X            goto loop;
  517. X        }
  518. X        if (c == '\n')
  519. X            unterminated_string(s_lineno, s_line, s_cptr);
  520. X        if (c == '\\')
  521. X        {
  522. X            c = *cptr++;
  523. X            putc(c, text_file);
  524. X            if (dflag) putc(c, union_file);
  525. X            if (c == '\n')
  526. X            {
  527. X            get_line();
  528. X            if (line == 0)
  529. X                unterminated_string(s_lineno, s_line, s_cptr);
  530. X            }
  531. X        }
  532. X        }
  533. X    }
  534. X
  535. X    case '/':
  536. X    c = *cptr;
  537. X    if (c == '/')
  538. X    {
  539. X        putc('*', text_file);
  540. X        if (dflag) putc('*', union_file);
  541. X        while ((c = *++cptr) != '\n')
  542. X        {
  543. X        if (c == '*' && cptr[1] == '/')
  544. X        {
  545. X            fprintf(text_file, "* ");
  546. X            if (dflag) fprintf(union_file, "* ");
  547. X        }
  548. X        else
  549. X        {
  550. X            putc(c, text_file);
  551. X            if (dflag) putc(c, union_file);
  552. X        }
  553. X        }
  554. X        fprintf(text_file, "*/\n");
  555. X        if (dflag) fprintf(union_file, "*/\n");
  556. X        goto next_line;
  557. X    }
  558. X    if (c == '*')
  559. X    {
  560. X        int c_lineno = lineno;
  561. X        char *c_line = dup_line();
  562. X        char *c_cptr = c_line + (cptr - line - 1);
  563. X
  564. X        putc('*', text_file);
  565. X        if (dflag) putc('*', union_file);
  566. X        ++cptr;
  567. X        for (;;)
  568. X        {
  569. X        c = *cptr++;
  570. X        putc(c, text_file);
  571. X        if (dflag) putc(c, union_file);
  572. X        if (c == '*' && *cptr == '/')
  573. X        {
  574. X            putc('/', text_file);
  575. X            if (dflag) putc('/', union_file);
  576. X            ++cptr;
  577. X            FREE(c_line);
  578. X            goto loop;
  579. X        }
  580. X        if (c == '\n')
  581. X        {
  582. X            get_line();
  583. X            if (line == 0)
  584. X            unterminated_comment(c_lineno, c_line, c_cptr);
  585. X        }
  586. X        }
  587. X    }
  588. X    goto loop;
  589. X
  590. X    default:
  591. X    goto loop;
  592. X    }
  593. X}
  594. X
  595. X
  596. Xint
  597. Xhexval(c)
  598. Xint c;
  599. X{
  600. X    if (c >= '0' && c <= '9')
  601. X    return (c - '0');
  602. X    if (c >= 'A' && c <= 'F')
  603. X    return (c - 'A' + 10);
  604. X    if (c >= 'a' && c <= 'f')
  605. X    return (c - 'a' + 10);
  606. X    return (-1);
  607. X}
  608. X
  609. X
  610. Xbucket *
  611. Xget_literal()
  612. X{
  613. X    register int c, quote;
  614. X    register int i;
  615. X    register int n;
  616. X    register char *s;
  617. X    register bucket *bp;
  618. X    int s_lineno = lineno;
  619. X    char *s_line = dup_line();
  620. X    char *s_cptr = s_line + (cptr - line);
  621. X
  622. X    quote = *cptr++;
  623. X    cinc = 0;
  624. X    for (;;)
  625. X    {
  626. X    c = *cptr++;
  627. X    if (c == quote) break;
  628. X    if (c == '\n') unterminated_string(s_lineno, s_line, s_cptr);
  629. X    if (c == '\\')
  630. X    {
  631. X        char *c_cptr = cptr - 1;
  632. X
  633. X        c = *cptr++;
  634. X        switch (c)
  635. X        {
  636. X        case '\n':
  637. X        get_line();
  638. X        if (line == 0) unterminated_string(s_lineno, s_line, s_cptr);
  639. X        continue;
  640. X
  641. X        case '0': case '1': case '2': case '3':
  642. X        case '4': case '5': case '6': case '7':
  643. X        n = c - '0';
  644. X        c = *cptr;
  645. X        if (IS_OCTAL(c))
  646. X        {
  647. X            n = (n << 3) + (c - '0');
  648. X            c = *++cptr;
  649. X            if (IS_OCTAL(c))
  650. X            {
  651. X            n = (n << 3) + (c - '0');
  652. X            ++cptr;
  653. X            }
  654. X        }
  655. X        if (n > MAXCHAR) illegal_character(c_cptr);
  656. X        c = n;
  657. X            break;
  658. X
  659. X        case 'x':
  660. X        c = *cptr++;
  661. X        n = hexval(c);
  662. X        if (n < 0 || n >= 16)
  663. X            illegal_character(c_cptr);
  664. X        for (;;)
  665. X        {
  666. X            c = *cptr;
  667. X            i = hexval(c);
  668. X            if (i < 0 || i >= 16) break;
  669. X            ++cptr;
  670. X            n = (n << 4) + i;
  671. X            if (n > MAXCHAR) illegal_character(c_cptr);
  672. X        }
  673. X        c = n;
  674. X        break;
  675. X
  676. X        case 'a': c = 7; break;
  677. X        case 'b': c = '\b'; break;
  678. X        case 'f': c = '\f'; break;
  679. X        case 'n': c = '\n'; break;
  680. X        case 'r': c = '\r'; break;
  681. X        case 't': c = '\t'; break;
  682. X        case 'v': c = '\v'; break;
  683. X        }
  684. X    }
  685. X    cachec(c);
  686. X    }
  687. X    FREE(s_line);
  688. X
  689. X    n = cinc;
  690. X    s = MALLOC(n);
  691. X    if (s == 0) no_space();
  692. X    
  693. X    for (i = 0; i < n; ++i)
  694. X    s[i] = cache[i];
  695. X
  696. X    cinc = 0;
  697. X    if (n == 1)
  698. X    cachec('\'');
  699. X    else
  700. X    cachec('"');
  701. X
  702. X    for (i = 0; i < n; ++i)
  703. X    {
  704. X    c = ((unsigned char *)s)[i];
  705. X    if (c == '\\' || c == cache[0])
  706. X    {
  707. X        cachec('\\');
  708. X        cachec(c);
  709. X    }
  710. X    else if (isprint(c))
  711. X        cachec(c);
  712. X    else
  713. X    {
  714. X        cachec('\\');
  715. X        switch (c)
  716. X        {
  717. X        case 7: cachec('a'); break;
  718. X        case '\b': cachec('b'); break;
  719. X        case '\f': cachec('f'); break;
  720. X        case '\n': cachec('n'); break;
  721. X        case '\r': cachec('r'); break;
  722. X        case '\t': cachec('t'); break;
  723. X        case '\v': cachec('v'); break;
  724. X        default:
  725. X        cachec(((c >> 6) & 7) + '0');
  726. X        cachec(((c >> 3) & 7) + '0');
  727. X        cachec((c & 7) + '0');
  728. X        break;
  729. X        }
  730. X    }
  731. X    }
  732. X
  733. X    if (n == 1)
  734. X    cachec('\'');
  735. X    else
  736. X    cachec('"');
  737. X
  738. X    cachec(NUL);
  739. X    bp = lookup(cache);
  740. X    bp->class = TERM;
  741. X    if (n == 1 && bp->value == UNDEFINED)
  742. X    bp->value = *(unsigned char *)s;
  743. X    FREE(s);
  744. X
  745. X    return (bp);
  746. X}
  747. X
  748. X
  749. Xint
  750. Xis_reserved(name)
  751. Xchar *name;
  752. X{
  753. X    char *s;
  754. X
  755. X    if (strcmp(name, ".") == 0 ||
  756. X        strcmp(name, "$accept") == 0 ||
  757. X        strcmp(name, "$end") == 0)
  758. X    return (1);
  759. X
  760. X    if (name[0] == '$' && name[1] == '$' && isdigit(name[2]))
  761. X    {
  762. X    s = name + 3;
  763. X    while (isdigit(*s)) ++s;
  764. X    if (*s == NUL) return (1);
  765. X    }
  766. X
  767. X    return (0);
  768. X}
  769. X
  770. X
  771. Xbucket *
  772. Xget_name()
  773. X{
  774. X    register int c;
  775. X
  776. X    cinc = 0;
  777. X    for (c = *cptr; IS_IDENT(c); c = *++cptr)
  778. X    cachec(c);
  779. X    cachec(NUL);
  780. X
  781. X    if (is_reserved(cache)) used_reserved(cache);
  782. X
  783. X    return (lookup(cache));
  784. X}
  785. X
  786. X
  787. Xint
  788. Xget_number()
  789. X{
  790. X    register int c;
  791. X    register int n;
  792. X
  793. X    n = 0;
  794. X    for (c = *cptr; isdigit(c); c = *++cptr)
  795. X    n = 10*n + (c - '0');
  796. X
  797. X    return (n);
  798. X}
  799. X
  800. X
  801. Xchar *
  802. Xget_tag()
  803. X{
  804. X    register int c;
  805. X    register int i;
  806. X    register char *s;
  807. X    int t_lineno = lineno;
  808. X    char *t_line = dup_line();
  809. X    char *t_cptr = t_line + (cptr - line);
  810. X
  811. X    ++cptr;
  812. X    c = nextc();
  813. X    if (c == EOF) unexpected_EOF();
  814. X    if (!isalpha(c) && c != '_' && c != '$')
  815. X    illegal_tag(t_lineno, t_line, t_cptr);
  816. X
  817. X    cinc = 0;
  818. X    do { cachec(c); c = *++cptr; } while (IS_IDENT(c));
  819. X    cachec(NUL);
  820. X
  821. X    c = nextc();
  822. X    if (c == EOF) unexpected_EOF();
  823. X    if (c != '>')
  824. X    illegal_tag(t_lineno, t_line, t_cptr);
  825. X    ++cptr;
  826. X
  827. X    for (i = 0; i < ntags; ++i)
  828. X    {
  829. X    if (strcmp(cache, tag_table[i]) == 0)
  830. X        return (tag_table[i]);
  831. X    }
  832. X
  833. X    if (ntags >= tagmax)
  834. X    {
  835. X    tagmax += 16;
  836. X    tag_table = (char **)
  837. X            (tag_table ? REALLOC(tag_table, tagmax*sizeof(char *))
  838. X                   : MALLOC(tagmax*sizeof(char *)));
  839. X    if (tag_table == 0) no_space();
  840. X    }
  841. X
  842. X    s = MALLOC(cinc);
  843. X    if  (s == 0) no_space();
  844. X    strcpy(s, cache);
  845. X    tag_table[ntags] = s;
  846. X    ++ntags;
  847. X    FREE(t_line);
  848. X    return (s);
  849. X}
  850. X
  851. X
  852. Xdeclare_tokens(assoc)
  853. Xint assoc;
  854. X{
  855. X    register int c;
  856. X    register bucket *bp;
  857. X    int value;
  858. X    char *tag = 0;
  859. X
  860. X    if (assoc != TOKEN) ++prec;
  861. X
  862. X    c = nextc();
  863. X    if (c == EOF) unexpected_EOF();
  864. X    if (c == '<')
  865. X    {
  866. X    tag = get_tag();
  867. X    c = nextc();
  868. X    if (c == EOF) unexpected_EOF();
  869. X    }
  870. X
  871. X    for (;;)
  872. X    {
  873. X    if (isalpha(c) || c == '_' || c == '.' || c == '$')
  874. X        bp = get_name();
  875. X    else if (c == '\'' || c == '"')
  876. X        bp = get_literal();
  877. X    else
  878. X        return;
  879. X
  880. X    if (bp == goal) tokenized_start(bp->name);
  881. X    bp->class = TERM;
  882. X
  883. X    if (tag)
  884. X    {
  885. X        if (bp->tag && tag != bp->tag)
  886. X        retyped_warning(bp->name);
  887. X        bp->tag = tag;
  888. X    }
  889. X
  890. X    if (assoc != TOKEN)
  891. X    {
  892. X        if (bp->prec && prec != bp->prec)
  893. X        reprec_warning(bp->name);
  894. X        bp->assoc = assoc;
  895. X        bp->prec = prec;
  896. X    }
  897. X
  898. X    c = nextc();
  899. X    if (c == EOF) unexpected_EOF();
  900. X    value = UNDEFINED;
  901. X    if (isdigit(c))
  902. X    {
  903. X        value = get_number();
  904. X        if (bp->value != UNDEFINED && value != bp->value)
  905. X        revalued_warning(bp->name);
  906. X        bp->value = value;
  907. X        c = nextc();
  908. X        if (c == EOF) unexpected_EOF();
  909. X    }
  910. X    }
  911. X}
  912. X
  913. X
  914. Xdeclare_types()
  915. X{
  916. X    register int c;
  917. X    register bucket *bp;
  918. X    char *tag;
  919. X
  920. X    c = nextc();
  921. X    if (c == EOF) unexpected_EOF();
  922. X    if (c != '<') syntax_error(lineno, line, cptr);
  923. X    tag = get_tag();
  924. X
  925. X    for (;;)
  926. X    {
  927. X    c = nextc();
  928. X    if (isalpha(c) || c == '_' || c == '.' || c == '$')
  929. X        bp = get_name();
  930. X    else if (c == '\'' || c == '"')
  931. X        bp = get_literal();
  932. X    else
  933. X        return;
  934. X
  935. X    if (bp->tag && tag != bp->tag)
  936. X        retyped_warning(bp->name);
  937. X    bp->tag = tag;
  938. X    }
  939. X}
  940. X
  941. X
  942. Xdeclare_start()
  943. X{
  944. X    register int c;
  945. X    register bucket *bp;
  946. X
  947. X    c = nextc();
  948. X    if (c == EOF) unexpected_EOF();
  949. X    if (!isalpha(c) && c != '_' && c != '.' && c != '$')
  950. X    syntax_error(lineno, line, cptr);
  951. X    bp = get_name();
  952. X    if (bp->class == TERM)
  953. X    terminal_start(bp->name);
  954. X    if (goal && goal != bp)
  955. X    restarted_warning();
  956. X    goal = bp;
  957. X}
  958. X
  959. X
  960. Xread_declarations()
  961. X{
  962. X    register int c, k;
  963. X
  964. X    cache_size = 256;
  965. X    cache = MALLOC(cache_size);
  966. X    if (cache == 0) no_space();
  967. X
  968. X    for (;;)
  969. X    {
  970. X    c = nextc();
  971. X    if (c == EOF) unexpected_EOF();
  972. X    if (c != '%') syntax_error(lineno, line, cptr);
  973. X    switch (k = keyword())
  974. X    {
  975. X    case MARK:
  976. X        return;
  977. X
  978. X    case IDENT:
  979. X        copy_ident();
  980. X        break;
  981. X
  982. X    case TEXT:
  983. X        copy_text();
  984. X        break;
  985. X
  986. X    case UNION:
  987. X        copy_union();
  988. X        break;
  989. X
  990. X    case TOKEN:
  991. X    case LEFT:
  992. X    case RIGHT:
  993. X    case NONASSOC:
  994. X        declare_tokens(k);
  995. X        break;
  996. X
  997. X    case TYPE:
  998. X        declare_types();
  999. X        break;
  1000. X
  1001. X    case START:
  1002. X        declare_start();
  1003. X        break;
  1004. X    }
  1005. X    }
  1006. X}
  1007. X
  1008. X
  1009. Xinitialize_grammar()
  1010. X{
  1011. X    nitems = 4;
  1012. X    maxitems = 300;
  1013. X    pitem = (bucket **) MALLOC(maxitems*sizeof(bucket *));
  1014. X    if (pitem == 0) no_space();
  1015. X    pitem[0] = 0;
  1016. X    pitem[1] = 0;
  1017. X    pitem[2] = 0;
  1018. X    pitem[3] = 0;
  1019. X
  1020. X    nrules = 3;
  1021. X    maxrules = 100;
  1022. X    plhs = (bucket **) MALLOC(maxrules*sizeof(bucket *));
  1023. X    if (plhs == 0) no_space();
  1024. X    plhs[0] = 0;
  1025. X    plhs[1] = 0;
  1026. X    plhs[2] = 0;
  1027. X    rprec = (short *) MALLOC(maxrules*sizeof(short));
  1028. X    if (rprec == 0) no_space();
  1029. X    rprec[0] = 0;
  1030. X    rprec[1] = 0;
  1031. X    rprec[2] = 0;
  1032. X    rassoc = (char *) MALLOC(maxrules*sizeof(char));
  1033. X    if (rassoc == 0) no_space();
  1034. X    rassoc[0] = TOKEN;
  1035. X    rassoc[1] = TOKEN;
  1036. X    rassoc[2] = TOKEN;
  1037. X}
  1038. X
  1039. X
  1040. Xexpand_items()
  1041. X{
  1042. X    maxitems += 300;
  1043. X    pitem = (bucket **) REALLOC(pitem, maxitems*sizeof(bucket *));
  1044. X    if (pitem == 0) no_space();
  1045. X}
  1046. X
  1047. X
  1048. Xexpand_rules()
  1049. X{
  1050. X    maxrules += 100;
  1051. X    plhs = (bucket **) REALLOC(plhs, maxrules*sizeof(bucket *));
  1052. X    if (plhs == 0) no_space();
  1053. X    rprec = (short *) REALLOC(rprec, maxrules*sizeof(short));
  1054. X    if (rprec == 0) no_space();
  1055. X    rassoc = (char *) REALLOC(rassoc, maxrules*sizeof(char));
  1056. X    if (rassoc == 0) no_space();
  1057. X}
  1058. X
  1059. X
  1060. Xadvance_to_start()
  1061. X{
  1062. X    register int c;
  1063. X    register bucket *bp;
  1064. X    char *s_cptr;
  1065. X    int s_lineno;
  1066. X
  1067. X    for (;;)
  1068. X    {
  1069. X    c = nextc();
  1070. X    if (c != '%') break;
  1071. X    s_cptr = cptr;
  1072. X    switch (keyword())
  1073. X    {
  1074. X    case MARK:
  1075. X        no_grammar();
  1076. X
  1077. X    case TEXT:
  1078. X        copy_text();
  1079. X        break;
  1080. X
  1081. X    case START:
  1082. X        declare_start();
  1083. X        break;
  1084. X
  1085. X    default:
  1086. X        syntax_error(lineno, line, s_cptr);
  1087. X    }
  1088. X    }
  1089. X
  1090. X    c = nextc();
  1091. X    if (!isalpha(c) && c != '_' && c != '.' && c != '_')
  1092. X    syntax_error(lineno, line, cptr);
  1093. X    bp = get_name();
  1094. X    if (goal == 0)
  1095. X    {
  1096. X    if (bp->class == TERM)
  1097. X        terminal_start(bp->name);
  1098. X    goal = bp;
  1099. X    }
  1100. X
  1101. X    s_lineno = lineno;
  1102. X    c = nextc();
  1103. X    if (c == EOF) unexpected_EOF();
  1104. X    if (c != ':') syntax_error(lineno, line, cptr);
  1105. X    start_rule(bp, s_lineno);
  1106. X    ++cptr;
  1107. X}
  1108. X
  1109. X
  1110. Xstart_rule(bp, s_lineno)
  1111. Xregister bucket *bp;
  1112. Xint s_lineno;
  1113. X{
  1114. X    if (bp->class == TERM)
  1115. X    terminal_lhs(s_lineno);
  1116. X    bp->class = NONTERM;
  1117. X    if (nrules >= maxrules)
  1118. X    expand_rules();
  1119. X    plhs[nrules] = bp;
  1120. X    rprec[nrules] = UNDEFINED;
  1121. X    rassoc[nrules] = TOKEN;
  1122. X}
  1123. X
  1124. X
  1125. Xend_rule()
  1126. X{
  1127. X    register int i;
  1128. X
  1129. X    if (!last_was_action && plhs[nrules]->tag)
  1130. X    {
  1131. X    for (i = nitems - 1; pitem[i]; --i) continue;
  1132. X    if (pitem[i+1]->tag != plhs[nrules]->tag)
  1133. X        default_action_warning();
  1134. X    }
  1135. X
  1136. X    last_was_action = 0;
  1137. X    if (nitems >= maxitems) expand_items();
  1138. X    pitem[nitems] = 0;
  1139. X    ++nitems;
  1140. X    ++nrules;
  1141. X}
  1142. X
  1143. X
  1144. Xinsert_empty_rule()
  1145. X{
  1146. X    register bucket *bp, **bpp;
  1147. X
  1148. X    assert(cache);
  1149. X    sprintf(cache, "$$%d", ++gensym);
  1150. X    bp = make_bucket(cache);
  1151. X    last_symbol->next = bp;
  1152. X    last_symbol = bp;
  1153. X    bp->tag = plhs[nrules]->tag;
  1154. X    bp->class = NONTERM;
  1155. X
  1156. X    if ((nitems += 2) > maxitems)
  1157. X    expand_items();
  1158. X    bpp = pitem + nitems - 1;
  1159. X    *bpp-- = bp;
  1160. X    while (bpp[0] = bpp[-1]) --bpp;
  1161. X
  1162. X    if (++nrules >= maxrules)
  1163. X    expand_rules();
  1164. X    plhs[nrules] = plhs[nrules-1];
  1165. X    plhs[nrules-1] = bp;
  1166. X    rprec[nrules] = rprec[nrules-1];
  1167. X    rprec[nrules-1] = 0;
  1168. X    rassoc[nrules] = rassoc[nrules-1];
  1169. X    rassoc[nrules-1] = TOKEN;
  1170. X}
  1171. X
  1172. X
  1173. Xadd_symbol()
  1174. X{
  1175. X    register int c;
  1176. X    register bucket *bp;
  1177. X    int s_lineno = lineno;
  1178. X
  1179. X    c = *cptr;
  1180. X    if (c == '\'' || c == '"')
  1181. X    bp = get_literal();
  1182. X    else
  1183. X    bp = get_name();
  1184. X
  1185. X    c = nextc();
  1186. X    if (c == ':')
  1187. X    {
  1188. X    end_rule();
  1189. X    start_rule(bp, s_lineno);
  1190. X    ++cptr;
  1191. X    return;
  1192. X    }
  1193. X
  1194. X    if (last_was_action)
  1195. X    insert_empty_rule();
  1196. X    last_was_action = 0;
  1197. X
  1198. X    if (++nitems > maxitems)
  1199. X    expand_items();
  1200. X    pitem[nitems-1] = bp;
  1201. X}
  1202. X
  1203. X
  1204. Xcopy_action()
  1205. X{
  1206. X    register int c;
  1207. X    register int i, n;
  1208. X    int depth;
  1209. X    int quote;
  1210. X    char *tag;
  1211. X    register FILE *f = action_file;
  1212. X    int a_lineno = lineno;
  1213. X    char *a_line = dup_line();
  1214. X    char *a_cptr = a_line + (cptr - line);
  1215. X
  1216. X    if (last_was_action)
  1217. X    insert_empty_rule();
  1218. X    last_was_action = 1;
  1219. X
  1220. X    fprintf(f, "case %d:\n", nrules - 2);
  1221. X    if (!lflag)
  1222. X    fprintf(f, line_format, lineno, input_file_name);
  1223. X    if (*cptr == '=') ++cptr;
  1224. X
  1225. X    n = 0;
  1226. X    for (i = nitems - 1; pitem[i]; --i) ++n;
  1227. X
  1228. X    depth = 0;
  1229. Xloop:
  1230. X    c = *cptr;
  1231. X    if (c == '$')
  1232. X    {
  1233. X    if (cptr[1] == '<')
  1234. X    {
  1235. X        int d_lineno = lineno;
  1236. X        char *d_line = dup_line();
  1237. X        char *d_cptr = d_line + (cptr - line);
  1238. X
  1239. X        ++cptr;
  1240. X        tag = get_tag();
  1241. X        c = *cptr;
  1242. X        if (c == '$')
  1243. X        {
  1244. X        fprintf(f, "yyval.%s ", tag);
  1245. X        ++cptr;
  1246. X        FREE(d_line);
  1247. X        goto loop;
  1248. X        }
  1249. X        else if (isdigit(c))
  1250. X        {
  1251. X        i = get_number();
  1252. X        if (i > n) dollar_warning(d_lineno, i);
  1253. X        fprintf(f, "yyvsp[%d].%s ", i - n, tag);
  1254. X        FREE(d_line);
  1255. X        goto loop;
  1256. X        }
  1257. X        else if (c == '-' && isdigit(cptr[1]))
  1258. X        {
  1259. X        ++cptr;
  1260. X        i = -get_number() - n;
  1261. X        fprintf(f, "yyvsp[%d].%s ", i, tag);
  1262. X        FREE(d_line);
  1263. X        goto loop;
  1264. X        }
  1265. X        else
  1266. X        dollar_error(d_lineno, d_line, d_cptr);
  1267. X    }
  1268. X    else if (cptr[1] == '$')
  1269. X    {
  1270. X        if (ntags)
  1271. X        {
  1272. X        tag = plhs[nrules]->tag;
  1273. X        if (tag == 0) untyped_lhs();
  1274. X        fprintf(f, "yyval.%s ", tag);
  1275. X        }
  1276. X        else
  1277. X        fprintf(f, "yyval ");
  1278. X        cptr += 2;
  1279. X        goto loop;
  1280. X    }
  1281. X    else if (isdigit(cptr[1]))
  1282. X    {
  1283. X        ++cptr;
  1284. X        i = get_number();
  1285. X        if (ntags)
  1286. X        {
  1287. X        if (i <= 0 || i > n)
  1288. X            unknown_rhs(i);
  1289. X        tag = pitem[nitems + i - n - 1]->tag;
  1290. X        if (tag == 0) untyped_rhs(i, pitem[nitems + i - n - 1]->name);
  1291. X        fprintf(f, "yyvsp[%d].%s ", i - n, tag);
  1292. X        }
  1293. X        else
  1294. X        {
  1295. X        if (i > n)
  1296. X            dollar_warning(lineno, i);
  1297. X        fprintf(f, "yyvsp[%d]", i - n);
  1298. X        }
  1299. X        goto loop;
  1300. X    }
  1301. X    else if (cptr[1] == '-')
  1302. X    {
  1303. X        cptr += 2;
  1304. X        i = get_number();
  1305. X        if (ntags)
  1306. X        unknown_rhs(-i);
  1307. X        fprintf(f, "yyvsp[%d]", -i - n);
  1308. X        goto loop;
  1309. X    }
  1310. X    }
  1311. X    if (isalpha(c) || c == '_' || c == '$')
  1312. X    {
  1313. X    do
  1314. X    {
  1315. X        putc(c, f);
  1316. X        c = *++cptr;
  1317. X    } while (isalnum(c) || c == '_' || c == '$');
  1318. X    goto loop;
  1319. X    }
  1320. X    putc(c, f);
  1321. X    ++cptr;
  1322. X    switch (c)
  1323. X    {
  1324. X    case '\n':
  1325. X    next_line:
  1326. X    get_line();
  1327. X    if (line) goto loop;
  1328. X    unterminated_action(a_lineno, a_line, a_cptr);
  1329. X
  1330. X    case ';':
  1331. X    if (depth > 0) goto loop;
  1332. X    fprintf(f, "\nbreak;\n");
  1333. X    return;
  1334. X
  1335. X    case '{':
  1336. X    ++depth;
  1337. X    goto loop;
  1338. X
  1339. X    case '}':
  1340. X    if (--depth > 0) goto loop;
  1341. X    fprintf(f, "\nbreak;\n");
  1342. X    return;
  1343. X
  1344. X    case '\'':
  1345. X    case '"':
  1346. X    {
  1347. X        int s_lineno = lineno;
  1348. X        char *s_line = dup_line();
  1349. X        char *s_cptr = s_line + (cptr - line - 1);
  1350. X
  1351. X        quote = c;
  1352. X        for (;;)
  1353. X        {
  1354. X        c = *cptr++;
  1355. X        putc(c, f);
  1356. X        if (c == quote)
  1357. X        {
  1358. X            FREE(s_line);
  1359. X            goto loop;
  1360. X        }
  1361. X        if (c == '\n')
  1362. X            unterminated_string(s_lineno, s_line, s_cptr);
  1363. X        if (c == '\\')
  1364. X        {
  1365. X            c = *cptr++;
  1366. X            putc(c, f);
  1367. X            if (c == '\n')
  1368. X            {
  1369. X            get_line();
  1370. X            if (line == 0)
  1371. X                unterminated_string(s_lineno, s_line, s_cptr);
  1372. X            }
  1373. X        }
  1374. X        }
  1375. X    }
  1376. X
  1377. X    case '/':
  1378. X    c = *cptr;
  1379. X    if (c == '/')
  1380. X    {
  1381. X        putc('*', f);
  1382. X        while ((c = *++cptr) != '\n')
  1383. X        {
  1384. X        if (c == '*' && cptr[1] == '/')
  1385. X            fprintf(f, "* ");
  1386. X        else
  1387. X            putc(c, f);
  1388. X        }
  1389. X        fprintf(f, "*/\n");
  1390. X        goto next_line;
  1391. X    }
  1392. X    if (c == '*')
  1393. X    {
  1394. X        int c_lineno = lineno;
  1395. X        char *c_line = dup_line();
  1396. X        char *c_cptr = c_line + (cptr - line - 1);
  1397. X
  1398. X        putc('*', f);
  1399. X        ++cptr;
  1400. X        for (;;)
  1401. X        {
  1402. X        c = *cptr++;
  1403. X        putc(c, f);
  1404. X        if (c == '*' && *cptr == '/')
  1405. X        {
  1406. X            putc('/', f);
  1407. X            ++cptr;
  1408. X            FREE(c_line);
  1409. X            goto loop;
  1410. X        }
  1411. X        if (c == '\n')
  1412. X        {
  1413. X            get_line();
  1414. X            if (line == 0)
  1415. X            unterminated_comment(c_lineno, c_line, c_cptr);
  1416. X        }
  1417. X        }
  1418. X    }
  1419. X    goto loop;
  1420. X
  1421. X    default:
  1422. X    goto loop;
  1423. X    }
  1424. X}
  1425. X
  1426. X
  1427. Xint
  1428. Xmark_symbol()
  1429. X{
  1430. X    register int c;
  1431. X    register bucket *bp;
  1432. X
  1433. X    c = cptr[1];
  1434. X    if (c == '%' || c == '\\')
  1435. X    {
  1436. X    cptr += 2;
  1437. X    return (1);
  1438. X    }
  1439. X
  1440. X    if (c == '=')
  1441. X    cptr += 2;
  1442. X    else if ((c == 'p' || c == 'P') &&
  1443. X         ((c = cptr[2]) == 'r' || c == 'R') &&
  1444. X         ((c = cptr[3]) == 'e' || c == 'E') &&
  1445. X         ((c = cptr[4]) == 'c' || c == 'C') &&
  1446. X         ((c = cptr[5], !IS_IDENT(c))))
  1447. X    cptr += 5;
  1448. X    else
  1449. X    syntax_error(lineno, line, cptr);
  1450. X
  1451. X    c = nextc();
  1452. X    if (isalpha(c) || c == '_' || c == '.' || c == '$')
  1453. X    bp = get_name();
  1454. X    else if (c == '\'' || c == '"')
  1455. X    bp = get_literal();
  1456. X    else
  1457. X    {
  1458. X    syntax_error(lineno, line, cptr);
  1459. X    /*NOTREACHED*/
  1460. X    }
  1461. X
  1462. X    if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
  1463. X    prec_redeclared();
  1464. X
  1465. X    rprec[nrules] = bp->prec;
  1466. X    rassoc[nrules] = bp->assoc;
  1467. X    return (0);
  1468. X}
  1469. X
  1470. X
  1471. Xread_grammar()
  1472. X{
  1473. X    register int c;
  1474. X
  1475. X    initialize_grammar();
  1476. X    advance_to_start();
  1477. X
  1478. X    for (;;)
  1479. X    {
  1480. X    c = nextc();
  1481. X    if (c == EOF) break;
  1482. X    if (isalpha(c) || c == '_' || c == '.' || c == '$' || c == '\'' ||
  1483. X        c == '"')
  1484. X        add_symbol();
  1485. X    else if (c == '{' || c == '=')
  1486. X        copy_action();
  1487. X    else if (c == '|')
  1488. X    {
  1489. X        end_rule();
  1490. X        start_rule(plhs[nrules-1], 0);
  1491. X        ++cptr;
  1492. X    }
  1493. X    else if (c == '%')
  1494. X    {
  1495. X        if (mark_symbol()) break;
  1496. X    }
  1497. X    else
  1498. X        syntax_error(lineno, line, cptr);
  1499. X    }
  1500. X    end_rule();
  1501. X}
  1502. X
  1503. X
  1504. Xfree_tags()
  1505. X{
  1506. X    register int i;
  1507. X
  1508. X    if (tag_table == 0) return;
  1509. X
  1510. X    for (i = 0; i < ntags; ++i)
  1511. X    {
  1512. X    assert(tag_table[i]);
  1513. X    FREE(tag_table[i]);
  1514. X    }
  1515. X    FREE(tag_table);
  1516. X}
  1517. X
  1518. X
  1519. Xpack_names()
  1520. X{
  1521. X    register bucket *bp;
  1522. X    register char *p, *s, *t;
  1523. X
  1524. X    name_pool_size = 13;  /* 13 == sizeof("$end") + sizeof("$accept") */
  1525. X    for (bp = first_symbol; bp; bp = bp->next)
  1526. X    name_pool_size += strlen(bp->name) + 1;
  1527. X    name_pool = MALLOC(name_pool_size);
  1528. X    if (name_pool == 0) no_space();
  1529. X
  1530. X    strcpy(name_pool, "$accept");
  1531. X    strcpy(name_pool+8, "$end");
  1532. X    t = name_pool + 13;
  1533. X    for (bp = first_symbol; bp; bp = bp->next)
  1534. X    {
  1535. X    p = t;
  1536. X    s = bp->name;
  1537. X    while (*t++ = *s++) continue;
  1538. X    FREE(bp->name);
  1539. X    bp->name = p;
  1540. X    }
  1541. X}
  1542. X
  1543. X
  1544. Xcheck_symbols()
  1545. X{
  1546. X    register bucket *bp;
  1547. X
  1548. X    if (goal->class == UNKNOWN)
  1549. X    undefined_goal(goal->name);
  1550. X
  1551. X    for (bp = first_symbol; bp; bp = bp->next)
  1552. X    {
  1553. X    if (bp->class == UNKNOWN)
  1554. X    {
  1555. X        undefined_symbol_warning(bp->name);
  1556. X        bp->class = TERM;
  1557. X    }
  1558. X    }
  1559. X}
  1560. X
  1561. X
  1562. Xpack_symbols()
  1563. X{
  1564. X    register bucket *bp;
  1565. X    register bucket **v;
  1566. X    register int i, j, k, n;
  1567. X
  1568. X    nsyms = 2;
  1569. X    ntokens = 1;
  1570. X    for (bp = first_symbol; bp; bp = bp->next)
  1571. X    {
  1572. X    ++nsyms;
  1573. X    if (bp->class == TERM) ++ntokens;
  1574. X    }
  1575. X    start_symbol = ntokens;
  1576. X    nvars = nsyms - ntokens;
  1577. X
  1578. X    symbol_name = (char **) MALLOC(nsyms*sizeof(char *));
  1579. X    if (symbol_name == 0) no_space();
  1580. X    symbol_value = (short *) MALLOC(nsyms*sizeof(short));
  1581. X    if (symbol_value == 0) no_space();
  1582. X    symbol_prec = (short *) MALLOC(nsyms*sizeof(short));
  1583. X    if (symbol_prec == 0) no_space();
  1584. X    symbol_assoc = MALLOC(nsyms);
  1585. X    if (symbol_assoc == 0) no_space();
  1586. X
  1587. X    v = (bucket **) MALLOC(nsyms*sizeof(bucket *));
  1588. X    if (v == 0) no_space();
  1589. X
  1590. X    v[0] = 0;
  1591. X    v[start_symbol] = 0;
  1592. X
  1593. X    i = 1;
  1594. X    j = start_symbol + 1;
  1595. X    for (bp = first_symbol; bp; bp = bp->next)
  1596. X    {
  1597. X    if (bp->class == TERM)
  1598. X        v[i++] = bp;
  1599. X    else
  1600. X        v[j++] = bp;
  1601. X    }
  1602. X    assert(i == ntokens && j == nsyms);
  1603. X
  1604. X    for (i = 1; i < ntokens; ++i)
  1605. X    v[i]->index = i;
  1606. X
  1607. X    goal->index = start_symbol + 1;
  1608. X    k = start_symbol + 2;
  1609. X    while (++i < nsyms)
  1610. X    if (v[i] != goal)
  1611. X    {
  1612. X        v[i]->index = k;
  1613. X        ++k;
  1614. X    }
  1615. X
  1616. X    goal->value = 0;
  1617. X    k = 1;
  1618. X    for (i = start_symbol + 1; i < nsyms; ++i)
  1619. X    {
  1620. X    if (v[i] != goal)
  1621. X    {
  1622. X        v[i]->value = k;
  1623. X        ++k;
  1624. X    }
  1625. X    }
  1626. X
  1627. X    k = 0;
  1628. X    for (i = 1; i < ntokens; ++i)
  1629. X    {
  1630. X    n = v[i]->value;
  1631. X    if (n > 256)
  1632. X    {
  1633. X        for (j = k++; j > 0 && symbol_value[j-1] > n; --j)
  1634. X        symbol_value[j] = symbol_value[j-1];
  1635. X        symbol_value[j] = n;
  1636. X    }
  1637. X    }
  1638. X
  1639. X    if (v[1]->value == UNDEFINED)
  1640. X    v[1]->value = 256;
  1641. X
  1642. X    j = 0;
  1643. X    n = 257;
  1644. X    for (i = 2; i < ntokens; ++i)
  1645. X    {
  1646. X    if (v[i]->value == UNDEFINED)
  1647. X    {
  1648. X        while (j < k && n == symbol_value[j])
  1649. X        {
  1650. X        while (++j < k && n == symbol_value[j]) continue;
  1651. X        ++n;
  1652. X        }
  1653. X        v[i]->value = n;
  1654. X        ++n;
  1655. X    }
  1656. X    }
  1657. X
  1658. X    symbol_name[0] = name_pool + 8;
  1659. X    symbol_value[0] = 0;
  1660. X    symbol_prec[0] = 0;
  1661. X    symbol_assoc[0] = TOKEN;
  1662. X    for (i = 1; i < ntokens; ++i)
  1663. X    {
  1664. X    symbol_name[i] = v[i]->name;
  1665. X    symbol_value[i] = v[i]->value;
  1666. X    symbol_prec[i] = v[i]->prec;
  1667. X    symbol_assoc[i] = v[i]->assoc;
  1668. X    }
  1669. X    symbol_name[start_symbol] = name_pool;
  1670. X    symbol_value[start_symbol] = -1;
  1671. X    symbol_prec[start_symbol] = 0;
  1672. X    symbol_assoc[start_symbol] = TOKEN;
  1673. X    for (++i; i < nsyms; ++i)
  1674. X    {
  1675. X    k = v[i]->index;
  1676. X    symbol_name[k] = v[i]->name;
  1677. X    symbol_value[k] = v[i]->value;
  1678. X    symbol_prec[k] = v[i]->prec;
  1679. X    symbol_assoc[k] = v[i]->assoc;
  1680. X    }
  1681. X
  1682. X    FREE(v);
  1683. X}
  1684. X
  1685. X
  1686. Xpack_grammar()
  1687. X{
  1688. X    register int i, j;
  1689. X    int assoc, prec;
  1690. X
  1691. X    ritem = (short *) MALLOC(nitems*sizeof(short));
  1692. X    if (ritem == 0) no_space();
  1693. X    rlhs = (short *) MALLOC(nrules*sizeof(short));
  1694. X    if (rlhs == 0) no_space();
  1695. X    rrhs = (short *) MALLOC((nrules+1)*sizeof(short));
  1696. X    if (rrhs == 0) no_space();
  1697. X    rprec = (short *) REALLOC(rprec, nrules*sizeof(short));
  1698. X    if (rprec == 0) no_space();
  1699. X    rassoc = REALLOC(rassoc, nrules);
  1700. X    if (rassoc == 0) no_space();
  1701. X
  1702. X    ritem[0] = -1;
  1703. X    ritem[1] = goal->index;
  1704. X    ritem[2] = 0;
  1705. X    ritem[3] = -2;
  1706. X    rlhs[0] = 0;
  1707. X    rlhs[1] = 0;
  1708. X    rlhs[2] = start_symbol;
  1709. X    rrhs[0] = 0;
  1710. X    rrhs[1] = 0;
  1711. X    rrhs[2] = 1;
  1712. X
  1713. X    j = 4;
  1714. X    for (i = 3; i < nrules; ++i)
  1715. X    {
  1716. X    rlhs[i] = plhs[i]->index;
  1717. X    rrhs[i] = j;
  1718. X    assoc = TOKEN;
  1719. X    prec = 0;
  1720. X    while (pitem[j])
  1721. X    {
  1722. X        ritem[j] = pitem[j]->index;
  1723. X        if (pitem[j]->class == TERM)
  1724. X        {
  1725. X        prec = pitem[j]->prec;
  1726. X        assoc = pitem[j]->assoc;
  1727. X        }
  1728. X        ++j;
  1729. X    }
  1730. X    ritem[j] = -i;
  1731. X    ++j;
  1732. X    if (rprec[i] == UNDEFINED)
  1733. X    {
  1734. X        rprec[i] = prec;
  1735. X        rassoc[i] = assoc;
  1736. X    }
  1737. X    }
  1738. X    rrhs[i] = j;
  1739. X
  1740. X    FREE(plhs);
  1741. X    FREE(pitem);
  1742. X}
  1743. X
  1744. X
  1745. Xprint_grammar()
  1746. X{
  1747. X    register int i, j, k;
  1748. X    int spacing;
  1749. X    register FILE *f = verbose_file;
  1750. X
  1751. X    if (!vflag) return;
  1752. X
  1753. X    k = 1;
  1754. X    for (i = 2; i < nrules; ++i)
  1755. X    {
  1756. X    if (rlhs[i] != rlhs[i-1])
  1757. X    {
  1758. X        if (i != 2) fprintf(f, "\n");
  1759. X        fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
  1760. X        spacing = strlen(symbol_name[rlhs[i]]) + 1;
  1761. X    }
  1762. X    else
  1763. X    {
  1764. X        fprintf(f, "%4d  ", i - 2);
  1765. X        j = spacing;
  1766. X        while (--j >= 0) putc(' ', f);
  1767. X        putc('|', f);
  1768. X    }
  1769. X
  1770. X    while (ritem[k] >= 0)
  1771. X    {
  1772. X        fprintf(f, " %s", symbol_name[ritem[k]]);
  1773. X        ++k;
  1774. X    }
  1775. X    ++k;
  1776. X    putc('\n', f);
  1777. X    }
  1778. X}
  1779. X
  1780. X
  1781. Xreader()
  1782. X{
  1783. X    write_section(banner);
  1784. X    create_symbol_table();
  1785. X    read_declarations();
  1786. X    read_grammar();
  1787. X    free_symbol_table();
  1788. X    free_tags();
  1789. X    pack_names();
  1790. X    check_symbols();
  1791. X    pack_symbols();
  1792. X    pack_grammar();
  1793. X    free_symbols();
  1794. X    print_grammar();
  1795. X}
  1796. END_OF_FILE
  1797. if test 30471 -ne `wc -c <'reader.c'`; then
  1798.     echo shar: \"'reader.c'\" unpacked with wrong size!
  1799. fi
  1800. # end of 'reader.c'
  1801. fi
  1802. if test -f 'test/ftp.y' -a "${1}" != "-c" ; then 
  1803.   echo shar: Will not clobber existing file \"'test/ftp.y'\"
  1804. else
  1805. echo shar: Extracting \"'test/ftp.y'\" \(22998 characters\)
  1806. sed "s/^X//" >'test/ftp.y' <<'END_OF_FILE'
  1807. X/*
  1808. X * Copyright (c) 1985, 1988 Regents of the University of California.
  1809. X * All rights reserved.
  1810. X *
  1811. X * Redistribution and use in source and binary forms are permitted
  1812. X * provided that the above copyright notice and this paragraph are
  1813. X * duplicated in all such forms and that any documentation,
  1814. X * advertising materials, and other materials related to such
  1815. X * distribution and use acknowledge that the software was developed
  1816. X * by the University of California, Berkeley.  The name of the
  1817. X * University may not be used to endorse or promote products derived
  1818. X * from this software without specific prior written permission.
  1819. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  1820. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  1821. X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  1822. X *
  1823. X *    @(#)ftpcmd.y    5.20.1.1 (Berkeley) 3/2/89
  1824. X */
  1825. X
  1826. X/*
  1827. X * Grammar for FTP commands.
  1828. X * See RFC 959.
  1829. X */
  1830. X
  1831. X%{
  1832. X
  1833. X#ifndef lint
  1834. Xstatic char sccsid[] = "@(#)ftpcmd.y    5.20.1.1 (Berkeley) 3/2/89";
  1835. X#endif /* not lint */
  1836. X
  1837. X#include <sys/param.h>
  1838. X#include <sys/socket.h>
  1839. X
  1840. X#include <netinet/in.h>
  1841. X
  1842. X#include <arpa/ftp.h>
  1843. X
  1844. X#include <stdio.h>
  1845. X#include <signal.h>
  1846. X#include <ctype.h>
  1847. X#include <pwd.h>
  1848. X#include <setjmp.h>
  1849. X#include <syslog.h>
  1850. X#include <sys/stat.h>
  1851. X#include <time.h>
  1852. X
  1853. Xextern    struct sockaddr_in data_dest;
  1854. Xextern    int logged_in;
  1855. Xextern    struct passwd *pw;
  1856. Xextern    int guest;
  1857. Xextern    int logging;
  1858. Xextern    int type;
  1859. Xextern    int form;
  1860. Xextern    int debug;
  1861. Xextern    int timeout;
  1862. Xextern    int maxtimeout;
  1863. Xextern  int pdata;
  1864. Xextern    char hostname[], remotehost[];
  1865. Xextern    char proctitle[];
  1866. Xextern    char *globerr;
  1867. Xextern    int usedefault;
  1868. Xextern  int transflag;
  1869. Xextern  char tmpline[];
  1870. Xchar    **glob();
  1871. X
  1872. Xstatic    int cmd_type;
  1873. Xstatic    int cmd_form;
  1874. Xstatic    int cmd_bytesz;
  1875. Xchar    cbuf[512];
  1876. Xchar    *fromname;
  1877. X
  1878. Xchar    *index();
  1879. X%}
  1880. X
  1881. X%token
  1882. X    A    B    C    E    F    I
  1883. X    L    N    P    R    S    T
  1884. X
  1885. X    SP    CRLF    COMMA    STRING    NUMBER
  1886. X
  1887. X    USER    PASS    ACCT    REIN    QUIT    PORT
  1888. X    PASV    TYPE    STRU    MODE    RETR    STOR
  1889. X    APPE    MLFL    MAIL    MSND    MSOM    MSAM
  1890. X    MRSQ    MRCP    ALLO    REST    RNFR    RNTO
  1891. X    ABOR    DELE    CWD    LIST    NLST    SITE
  1892. X    STAT    HELP    NOOP    MKD    RMD    PWD
  1893. X    CDUP    STOU    SMNT    SYST    SIZE    MDTM
  1894. X
  1895. X    UMASK    IDLE    CHMOD
  1896. X
  1897. X    LEXERR
  1898. X
  1899. X%start    cmd_list
  1900. X
  1901. X%%
  1902. X
  1903. Xcmd_list:    /* empty */
  1904. X    |    cmd_list cmd
  1905. X        = {
  1906. X            fromname = (char *) 0;
  1907. X        }
  1908. X    |    cmd_list rcmd
  1909. X    ;
  1910. X
  1911. Xcmd:        USER SP username CRLF
  1912. X        = {
  1913. X            user((char *) $3);
  1914. X            free((char *) $3);
  1915. X        }
  1916. X    |    PASS SP password CRLF
  1917. X        = {
  1918. X            pass((char *) $3);
  1919. X            free((char *) $3);
  1920. X        }
  1921. X    |    PORT SP host_port CRLF
  1922. X        = {
  1923. X            usedefault = 0;
  1924. X            if (pdata >= 0) {
  1925. X                (void) close(pdata);
  1926. X                pdata = -1;
  1927. X            }
  1928. X            reply(200, "PORT command successful.");
  1929. X        }
  1930. X    |    PASV CRLF
  1931. X        = {
  1932. X            passive();
  1933. X        }
  1934. X    |    TYPE SP type_code CRLF
  1935. X        = {
  1936. X            switch (cmd_type) {
  1937. X
  1938. X            case TYPE_A:
  1939. X                if (cmd_form == FORM_N) {
  1940. X                    reply(200, "Type set to A.");
  1941. X                    type = cmd_type;
  1942. X                    form = cmd_form;
  1943. X                } else
  1944. X                    reply(504, "Form must be N.");
  1945. X                break;
  1946. X
  1947. X            case TYPE_E:
  1948. X                reply(504, "Type E not implemented.");
  1949. X                break;
  1950. X
  1951. X            case TYPE_I:
  1952. X                reply(200, "Type set to I.");
  1953. X                type = cmd_type;
  1954. X                break;
  1955. X
  1956. X            case TYPE_L:
  1957. X#if NBBY == 8
  1958. X                if (cmd_bytesz == 8) {
  1959. X                    reply(200,
  1960. X                        "Type set to L (byte size 8).");
  1961. X                    type = cmd_type;
  1962. X                } else
  1963. X                    reply(504, "Byte size must be 8.");
  1964. X#else /* NBBY == 8 */
  1965. X                UNIMPLEMENTED for NBBY != 8
  1966. X#endif /* NBBY == 8 */
  1967. X            }
  1968. X        }
  1969. X    |    STRU SP struct_code CRLF
  1970. X        = {
  1971. X            switch ($3) {
  1972. X
  1973. X            case STRU_F:
  1974. X                reply(200, "STRU F ok.");
  1975. X                break;
  1976. X
  1977. X            default:
  1978. X                reply(504, "Unimplemented STRU type.");
  1979. X            }
  1980. X        }
  1981. X    |    MODE SP mode_code CRLF
  1982. X        = {
  1983. X            switch ($3) {
  1984. X
  1985. X            case MODE_S:
  1986. X                reply(200, "MODE S ok.");
  1987. X                break;
  1988. X
  1989. X            default:
  1990. X                reply(502, "Unimplemented MODE type.");
  1991. X            }
  1992. X        }
  1993. X    |    ALLO SP NUMBER CRLF
  1994. X        = {
  1995. X            reply(202, "ALLO command ignored.");
  1996. X        }
  1997. X    |    ALLO SP NUMBER SP R SP NUMBER CRLF
  1998. X        = {
  1999. X            reply(202, "ALLO command ignored.");
  2000. X        }
  2001. X    |    RETR check_login SP pathname CRLF
  2002. X        = {
  2003. X            if ($2 && $4 != NULL)
  2004. X                retrieve((char *) 0, (char *) $4);
  2005. X            if ($4 != NULL)
  2006. X                free((char *) $4);
  2007. X        }
  2008. X    |    STOR check_login SP pathname CRLF
  2009. X        = {
  2010. X            if ($2 && $4 != NULL)
  2011. X                store((char *) $4, "w", 0);
  2012. X            if ($4 != NULL)
  2013. X                free((char *) $4);
  2014. X        }
  2015. X    |    APPE check_login SP pathname CRLF
  2016. X        = {
  2017. X            if ($2 && $4 != NULL)
  2018. X                store((char *) $4, "a", 0);
  2019. X            if ($4 != NULL)
  2020. X                free((char *) $4);
  2021. X        }
  2022. X    |    NLST check_login CRLF
  2023. X        = {
  2024. X            if ($2)
  2025. X                send_file_list(".");
  2026. X        }
  2027. X    |    NLST check_login SP STRING CRLF
  2028. X        = {
  2029. X            if ($2 && $4 != NULL) 
  2030. X                send_file_list((char *) $4);
  2031. X            if ($4 != NULL)
  2032. X                free((char *) $4);
  2033. X        }
  2034. X    |    LIST check_login CRLF
  2035. X        = {
  2036. X            if ($2)
  2037. X                retrieve("/bin/ls -lgA", "");
  2038. X        }
  2039. X    |    LIST check_login SP pathname CRLF
  2040. X        = {
  2041. X            if ($2 && $4 != NULL)
  2042. X                retrieve("/bin/ls -lgA %s", (char *) $4);
  2043. X            if ($4 != NULL)
  2044. X                free((char *) $4);
  2045. X        }
  2046. X    |    STAT check_login SP pathname CRLF
  2047. X        = {
  2048. X            if ($2 && $4 != NULL)
  2049. X                statfilecmd((char *) $4);
  2050. X            if ($4 != NULL)
  2051. X                free((char *) $4);
  2052. X        }
  2053. X    |    STAT CRLF
  2054. X        = {
  2055. X            statcmd();
  2056. X        }
  2057. X    |    DELE check_login SP pathname CRLF
  2058. X        = {
  2059. X            if ($2 && $4 != NULL)
  2060. X                delete((char *) $4);
  2061. X            if ($4 != NULL)
  2062. X                free((char *) $4);
  2063. X        }
  2064. X    |    RNTO SP pathname CRLF
  2065. X        = {
  2066. X            if (fromname) {
  2067. X                renamecmd(fromname, (char *) $3);
  2068. X                free(fromname);
  2069. X                fromname = (char *) 0;
  2070. X            } else {
  2071. X                reply(503, "Bad sequence of commands.");
  2072. X            }
  2073. X            free((char *) $3);
  2074. X        }
  2075. X    |    ABOR CRLF
  2076. X        = {
  2077. X            reply(225, "ABOR command successful.");
  2078. X        }
  2079. X    |    CWD check_login CRLF
  2080. X        = {
  2081. X            if ($2)
  2082. X                cwd(pw->pw_dir);
  2083. X        }
  2084. X    |    CWD check_login SP pathname CRLF
  2085. X        = {
  2086. X            if ($2 && $4 != NULL)
  2087. X                cwd((char *) $4);
  2088. X            if ($4 != NULL)
  2089. X                free((char *) $4);
  2090. X        }
  2091. X    |    HELP CRLF
  2092. X        = {
  2093. X            help(cmdtab, (char *) 0);
  2094. X        }
  2095. X    |    HELP SP STRING CRLF
  2096. X        = {
  2097. X            register char *cp = (char *)$3;
  2098. X
  2099. X            if (strncasecmp(cp, "SITE", 4) == 0) {
  2100. X                cp = (char *)$3 + 4;
  2101. X                if (*cp == ' ')
  2102. X                    cp++;
  2103. X                if (*cp)
  2104. X                    help(sitetab, cp);
  2105. X                else
  2106. X                    help(sitetab, (char *) 0);
  2107. X            } else
  2108. X                help(cmdtab, (char *) $3);
  2109. X        }
  2110. X    |    NOOP CRLF
  2111. X        = {
  2112. X            reply(200, "NOOP command successful.");
  2113. X        }
  2114. X    |    MKD check_login SP pathname CRLF
  2115. X        = {
  2116. X            if ($2 && $4 != NULL)
  2117. X                makedir((char *) $4);
  2118. X            if ($4 != NULL)
  2119. X                free((char *) $4);
  2120. X        }
  2121. X    |    RMD check_login SP pathname CRLF
  2122. X        = {
  2123. X            if ($2 && $4 != NULL)
  2124. X                removedir((char *) $4);
  2125. X            if ($4 != NULL)
  2126. X                free((char *) $4);
  2127. X        }
  2128. X    |    PWD check_login CRLF
  2129. X        = {
  2130. X            if ($2)
  2131. X                pwd();
  2132. X        }
  2133. X    |    CDUP check_login CRLF
  2134. X        = {
  2135. X            if ($2)
  2136. X                cwd("..");
  2137. X        }
  2138. X    |    SITE SP HELP CRLF
  2139. X        = {
  2140. X            help(sitetab, (char *) 0);
  2141. X        }
  2142. X    |    SITE SP HELP SP STRING CRLF
  2143. X        = {
  2144. X            help(sitetab, (char *) $5);
  2145. X        }
  2146. X    |    SITE SP UMASK check_login CRLF
  2147. X        = {
  2148. X            int oldmask;
  2149. X
  2150. X            if ($4) {
  2151. X                oldmask = umask(0);
  2152. X                (void) umask(oldmask);
  2153. X                reply(200, "Current UMASK is %03o", oldmask);
  2154. X            }
  2155. X        }
  2156. X    |    SITE SP UMASK check_login SP octal_number CRLF
  2157. X        = {
  2158. X            int oldmask;
  2159. X
  2160. X            if ($4) {
  2161. X                if (($6 == -1) || ($6 > 0777)) {
  2162. X                    reply(501, "Bad UMASK value");
  2163. X                } else {
  2164. X                    oldmask = umask($6);
  2165. X                    reply(200,
  2166. X                        "UMASK set to %03o (was %03o)",
  2167. X                        $6, oldmask);
  2168. X                }
  2169. X            }
  2170. X        }
  2171. X    |    SITE SP CHMOD check_login SP octal_number SP pathname CRLF
  2172. X        = {
  2173. X            if ($4 && ($8 != NULL)) {
  2174. X                if ($6 > 0777)
  2175. X                    reply(501,
  2176. X                "CHMOD: Mode value must be between 0 and 0777");
  2177. X                else if (chmod((char *) $8, $6) < 0)
  2178. X                    perror_reply(550, (char *) $8);
  2179. X                else
  2180. X                    reply(200, "CHMOD command successful.");
  2181. X            }
  2182. X            if ($8 != NULL)
  2183. X                free((char *) $8);
  2184. X        }
  2185. X    |    SITE SP IDLE CRLF
  2186. X        = {
  2187. X            reply(200,
  2188. X                "Current IDLE time limit is %d seconds; max %d",
  2189. X                timeout, maxtimeout);
  2190. X        }
  2191. X    |    SITE SP IDLE SP NUMBER CRLF
  2192. X        = {
  2193. X            if ($5 < 30 || $5 > maxtimeout) {
  2194. X                reply(501,
  2195. X            "Maximum IDLE time must be between 30 and %d seconds",
  2196. X                    maxtimeout);
  2197. X            } else {
  2198. X                timeout = $5;
  2199. X                (void) alarm((unsigned) timeout);
  2200. X                reply(200,
  2201. X                    "Maximum IDLE time set to %d seconds",
  2202. X                    timeout);
  2203. X            }
  2204. X        }
  2205. X    |    STOU check_login SP pathname CRLF
  2206. X        = {
  2207. X            if ($2 && $4 != NULL)
  2208. X                store((char *) $4, "w", 1);
  2209. X            if ($4 != NULL)
  2210. X                free((char *) $4);
  2211. X        }
  2212. X    |    SYST CRLF
  2213. X        = {
  2214. X#ifdef unix
  2215. X#ifdef BSD
  2216. X            reply(215, "UNIX Type: L%d Version: BSD-%d",
  2217. X                NBBY, BSD);
  2218. X#else /* BSD */
  2219. X            reply(215, "UNIX Type: L%d", NBBY);
  2220. X#endif /* BSD */
  2221. X#else /* unix */
  2222. X            reply(215, "UNKNOWN Type: L%d", NBBY);
  2223. X#endif /* unix */
  2224. X        }
  2225. X
  2226. X        /*
  2227. X         * SIZE is not in RFC959, but Postel has blessed it and
  2228. X         * it will be in the updated RFC.
  2229. X         *
  2230. X         * Return size of file in a format suitable for
  2231. X         * using with RESTART (we just count bytes).
  2232. X         */
  2233. X    |    SIZE check_login SP pathname CRLF
  2234. X        = {
  2235. X            if ($2 && $4 != NULL)
  2236. X                sizecmd((char *) $4);
  2237. X            if ($4 != NULL)
  2238. X                free((char *) $4);
  2239. X        }
  2240. X
  2241. X        /*
  2242. X         * MDTM is not in RFC959, but Postel has blessed it and
  2243. X         * it will be in the updated RFC.
  2244. X         *
  2245. X         * Return modification time of file as an ISO 3307
  2246. X         * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx
  2247. X         * where xxx is the fractional second (of any precision,
  2248. X         * not necessarily 3 digits)
  2249. X         */
  2250. X    |    MDTM check_login SP pathname CRLF
  2251. X        = {
  2252. X            if ($2 && $4 != NULL) {
  2253. X                struct stat stbuf;
  2254. X                if (stat((char *) $4, &stbuf) < 0)
  2255. X                    perror_reply(550, "%s", (char *) $4);
  2256. X                else if ((stbuf.st_mode&S_IFMT) != S_IFREG) {
  2257. X                    reply(550, "%s: not a plain file.",
  2258. X                        (char *) $4);
  2259. X                } else {
  2260. X                    register struct tm *t;
  2261. X                    struct tm *gmtime();
  2262. X                    t = gmtime(&stbuf.st_mtime);
  2263. X                    reply(213,
  2264. X                        "19%02d%02d%02d%02d%02d%02d",
  2265. X                        t->tm_year, t->tm_mon+1, t->tm_mday,
  2266. X                        t->tm_hour, t->tm_min, t->tm_sec);
  2267. X                }
  2268. X            }
  2269. X            if ($4 != NULL)
  2270. X                free((char *) $4);
  2271. X        }
  2272. X    |    QUIT CRLF
  2273. X        = {
  2274. X            reply(221, "Goodbye.");
  2275. X            dologout(0);
  2276. X        }
  2277. X    |    error CRLF
  2278. X        = {
  2279. X            yyerrok;
  2280. X        }
  2281. X    ;
  2282. Xrcmd:        RNFR check_login SP pathname CRLF
  2283. X        = {
  2284. X            char *renamefrom();
  2285. X
  2286. X            if ($2 && $4) {
  2287. X                fromname = renamefrom((char *) $4);
  2288. X                if (fromname == (char *) 0 && $4) {
  2289. X                    free((char *) $4);
  2290. X                }
  2291. X            }
  2292. X        }
  2293. X    ;
  2294. X        
  2295. Xusername:    STRING
  2296. X    ;
  2297. X
  2298. Xpassword:    /* empty */
  2299. X        = {
  2300. X            *(char **)&($$) = "";
  2301. X        }
  2302. X    |    STRING
  2303. X    ;
  2304. X
  2305. Xbyte_size:    NUMBER
  2306. X    ;
  2307. X
  2308. Xhost_port:    NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 
  2309. X        NUMBER COMMA NUMBER
  2310. X        = {
  2311. X            register char *a, *p;
  2312. X
  2313. X            a = (char *)&data_dest.sin_addr;
  2314. X            a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7;
  2315. X            p = (char *)&data_dest.sin_port;
  2316. X            p[0] = $9; p[1] = $11;
  2317. X            data_dest.sin_family = AF_INET;
  2318. X        }
  2319. X    ;
  2320. X
  2321. Xform_code:    N
  2322. X    = {
  2323. X        $$ = FORM_N;
  2324. X    }
  2325. X    |    T
  2326. X    = {
  2327. X        $$ = FORM_T;
  2328. X    }
  2329. X    |    C
  2330. X    = {
  2331. X        $$ = FORM_C;
  2332. X    }
  2333. X    ;
  2334. X
  2335. Xtype_code:    A
  2336. X    = {
  2337. X        cmd_type = TYPE_A;
  2338. X        cmd_form = FORM_N;
  2339. X    }
  2340. X    |    A SP form_code
  2341. X    = {
  2342. X        cmd_type = TYPE_A;
  2343. X        cmd_form = $3;
  2344. X    }
  2345. X    |    E
  2346. X    = {
  2347. X        cmd_type = TYPE_E;
  2348. X        cmd_form = FORM_N;
  2349. X    }
  2350. X    |    E SP form_code
  2351. X    = {
  2352. X        cmd_type = TYPE_E;
  2353. X        cmd_form = $3;
  2354. X    }
  2355. X    |    I
  2356. X    = {
  2357. X        cmd_type = TYPE_I;
  2358. X    }
  2359. X    |    L
  2360. X    = {
  2361. X        cmd_type = TYPE_L;
  2362. X        cmd_bytesz = NBBY;
  2363. X    }
  2364. X    |    L SP byte_size
  2365. X    = {
  2366. X        cmd_type = TYPE_L;
  2367. X        cmd_bytesz = $3;
  2368. X    }
  2369. X    /* this is for a bug in the BBN ftp */
  2370. X    |    L byte_size
  2371. X    = {
  2372. X        cmd_type = TYPE_L;
  2373. X        cmd_bytesz = $2;
  2374. X    }
  2375. X    ;
  2376. X
  2377. Xstruct_code:    F
  2378. X    = {
  2379. X        $$ = STRU_F;
  2380. X    }
  2381. X    |    R
  2382. X    = {
  2383. X        $$ = STRU_R;
  2384. X    }
  2385. X    |    P
  2386. X    = {
  2387. X        $$ = STRU_P;
  2388. X    }
  2389. X    ;
  2390. X
  2391. Xmode_code:    S
  2392. X    = {
  2393. X        $$ = MODE_S;
  2394. X    }
  2395. X    |    B
  2396. X    = {
  2397. X        $$ = MODE_B;
  2398. X    }
  2399. X    |    C
  2400. X    = {
  2401. X        $$ = MODE_C;
  2402. X    }
  2403. X    ;
  2404. X
  2405. Xpathname:    pathstring
  2406. X    = {
  2407. X        /*
  2408. X         * Problem: this production is used for all pathname
  2409. X         * processing, but only gives a 550 error reply.
  2410. X         * This is a valid reply in some cases but not in others.
  2411. X         */
  2412. X        if (logged_in && $1 && strncmp((char *) $1, "~", 1) == 0) {
  2413. X            *(char **)&($$) = *glob((char *) $1);
  2414. X            if (globerr != NULL) {
  2415. X                reply(550, globerr);
  2416. X                $$ = NULL;
  2417. X            }
  2418. X            free((char *) $1);
  2419. X        } else
  2420. X            $$ = $1;
  2421. X    }
  2422. X    ;
  2423. X
  2424. Xpathstring:    STRING
  2425. X    ;
  2426. X
  2427. Xoctal_number:    NUMBER
  2428. X    = {
  2429. X        register int ret, dec, multby, digit;
  2430. X
  2431. X        /*
  2432. X         * Convert a number that was read as decimal number
  2433. X         * to what it would be if it had been read as octal.
  2434. X         */
  2435. X        dec = $1;
  2436. X        multby = 1;
  2437. X        ret = 0;
  2438. X        while (dec) {
  2439. X            digit = dec%10;
  2440. X            if (digit > 7) {
  2441. X                ret = -1;
  2442. X                break;
  2443. X            }
  2444. X            ret += digit * multby;
  2445. X            multby *= 8;
  2446. X            dec /= 10;
  2447. X        }
  2448. X        $$ = ret;
  2449. X    }
  2450. X    ;
  2451. X
  2452. Xcheck_login:    /* empty */
  2453. X    = {
  2454. X        if (logged_in)
  2455. X            $$ = 1;
  2456. X        else {
  2457. X            reply(530, "Please login with USER and PASS.");
  2458. X            $$ = 0;
  2459. X        }
  2460. X    }
  2461. X    ;
  2462. X
  2463. X%%
  2464. X
  2465. Xextern jmp_buf errcatch;
  2466. X
  2467. X#define    CMD    0    /* beginning of command */
  2468. X#define    ARGS    1    /* expect miscellaneous arguments */
  2469. X#define    STR1    2    /* expect SP followed by STRING */
  2470. X#define    STR2    3    /* expect STRING */
  2471. X#define    OSTR    4    /* optional SP then STRING */
  2472. X#define    ZSTR1    5    /* SP then optional STRING */
  2473. X#define    ZSTR2    6    /* optional STRING after SP */
  2474. X#define    SITECMD    7    /* SITE command */
  2475. X#define    NSTR    8    /* Number followed by a string */
  2476. X
  2477. Xstruct tab {
  2478. X    char    *name;
  2479. X    short    token;
  2480. X    short    state;
  2481. X    short    implemented;    /* 1 if command is implemented */
  2482. X    char    *help;
  2483. X};
  2484. X
  2485. Xstruct tab cmdtab[] = {        /* In order defined in RFC 765 */
  2486. X    { "USER", USER, STR1, 1,    "<sp> username" },
  2487. X    { "PASS", PASS, ZSTR1, 1,    "<sp> password" },
  2488. X    { "ACCT", ACCT, STR1, 0,    "(specify account)" },
  2489. X    { "SMNT", SMNT, ARGS, 0,    "(structure mount)" },
  2490. X    { "REIN", REIN, ARGS, 0,    "(reinitialize server state)" },
  2491. X    { "QUIT", QUIT, ARGS, 1,    "(terminate service)", },
  2492. X    { "PORT", PORT, ARGS, 1,    "<sp> b0, b1, b2, b3, b4" },
  2493. X    { "PASV", PASV, ARGS, 1,    "(set server in passive mode)" },
  2494. X    { "TYPE", TYPE, ARGS, 1,    "<sp> [ A | E | I | L ]" },
  2495. X    { "STRU", STRU, ARGS, 1,    "(specify file structure)" },
  2496. X    { "MODE", MODE, ARGS, 1,    "(specify transfer mode)" },
  2497. X    { "RETR", RETR, STR1, 1,    "<sp> file-name" },
  2498. X    { "STOR", STOR, STR1, 1,    "<sp> file-name" },
  2499. X    { "APPE", APPE, STR1, 1,    "<sp> file-name" },
  2500. X    { "MLFL", MLFL, OSTR, 0,    "(mail file)" },
  2501. X    { "MAIL", MAIL, OSTR, 0,    "(mail to user)" },
  2502. X    { "MSND", MSND, OSTR, 0,    "(mail send to terminal)" },
  2503. X    { "MSOM", MSOM, OSTR, 0,    "(mail send to terminal or mailbox)" },
  2504. X    { "MSAM", MSAM, OSTR, 0,    "(mail send to terminal and mailbox)" },
  2505. X    { "MRSQ", MRSQ, OSTR, 0,    "(mail recipient scheme question)" },
  2506. X    { "MRCP", MRCP, STR1, 0,    "(mail recipient)" },
  2507. X    { "ALLO", ALLO, ARGS, 1,    "allocate storage (vacuously)" },
  2508. X    { "REST", REST, ARGS, 0,    "(restart command)" },
  2509. X    { "RNFR", RNFR, STR1, 1,    "<sp> file-name" },
  2510. X    { "RNTO", RNTO, STR1, 1,    "<sp> file-name" },
  2511. X    { "ABOR", ABOR, ARGS, 1,    "(abort operation)" },
  2512. X    { "DELE", DELE, STR1, 1,    "<sp> file-name" },
  2513. X    { "CWD",  CWD,  OSTR, 1,    "[ <sp> directory-name ]" },
  2514. X    { "XCWD", CWD,    OSTR, 1,    "[ <sp> directory-name ]" },
  2515. X    { "LIST", LIST, OSTR, 1,    "[ <sp> path-name ]" },
  2516. X    { "NLST", NLST, OSTR, 1,    "[ <sp> path-name ]" },
  2517. X    { "SITE", SITE, SITECMD, 1,    "site-cmd [ <sp> arguments ]" },
  2518. X    { "SYST", SYST, ARGS, 1,    "(get type of operating system)" },
  2519. X    { "STAT", STAT, OSTR, 1,    "[ <sp> path-name ]" },
  2520. X    { "HELP", HELP, OSTR, 1,    "[ <sp> <string> ]" },
  2521. X    { "NOOP", NOOP, ARGS, 1,    "" },
  2522. X    { "MKD",  MKD,  STR1, 1,    "<sp> path-name" },
  2523. X    { "XMKD", MKD,  STR1, 1,    "<sp> path-name" },
  2524. X    { "RMD",  RMD,  STR1, 1,    "<sp> path-name" },
  2525. X    { "XRMD", RMD,  STR1, 1,    "<sp> path-name" },
  2526. X    { "PWD",  PWD,  ARGS, 1,    "(return current directory)" },
  2527. X    { "XPWD", PWD,  ARGS, 1,    "(return current directory)" },
  2528. X    { "CDUP", CDUP, ARGS, 1,    "(change to parent directory)" },
  2529. X    { "XCUP", CDUP, ARGS, 1,    "(change to parent directory)" },
  2530. X    { "STOU", STOU, STR1, 1,    "<sp> file-name" },
  2531. X    { "SIZE", SIZE, OSTR, 1,    "<sp> path-name" },
  2532. X    { "MDTM", MDTM, OSTR, 1,    "<sp> path-name" },
  2533. X    { NULL,   0,    0,    0,    0 }
  2534. X};
  2535. X
  2536. Xstruct tab sitetab[] = {
  2537. X    { "UMASK", UMASK, ARGS, 1,    "[ <sp> umask ]" },
  2538. X    { "IDLE", IDLE, ARGS, 1,    "[ <sp> maximum-idle-time ]" },
  2539. X    { "CHMOD", CHMOD, NSTR, 1,    "<sp> mode <sp> file-name" },
  2540. X    { "HELP", HELP, OSTR, 1,    "[ <sp> <string> ]" },
  2541. X    { NULL,   0,    0,    0,    0 }
  2542. X};
  2543. X
  2544. Xstruct tab *
  2545. Xlookup(p, cmd)
  2546. X    register struct tab *p;
  2547. X    char *cmd;
  2548. X{
  2549. X
  2550. X    for (; p->name != NULL; p++)
  2551. X        if (strcmp(cmd, p->name) == 0)
  2552. X            return (p);
  2553. X    return (0);
  2554. X}
  2555. X
  2556. X#include <arpa/telnet.h>
  2557. X
  2558. X/*
  2559. X * getline - a hacked up version of fgets to ignore TELNET escape codes.
  2560. X */
  2561. Xchar *
  2562. Xgetline(s, n, iop)
  2563. X    char *s;
  2564. X    register FILE *iop;
  2565. X{
  2566. X    register c;
  2567. X    register char *cs;
  2568. X
  2569. X    cs = s;
  2570. X/* tmpline may contain saved command from urgent mode interruption */
  2571. X    for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) {
  2572. X        *cs++ = tmpline[c];
  2573. X        if (tmpline[c] == '\n') {
  2574. X            *cs++ = '\0';
  2575. X            if (debug)
  2576. X                syslog(LOG_DEBUG, "command: %s", s);
  2577. X            tmpline[0] = '\0';
  2578. X            return(s);
  2579. X        }
  2580. X        if (c == 0)
  2581. X            tmpline[0] = '\0';
  2582. X    }
  2583. X    while ((c = getc(iop)) != EOF) {
  2584. X        c &= 0377;
  2585. X        if (c == IAC) {
  2586. X            if ((c = getc(iop)) != EOF) {
  2587. X            c &= 0377;
  2588. X            switch (c) {
  2589. X            case WILL:
  2590. X            case WONT:
  2591. X                c = getc(iop);
  2592. X                printf("%c%c%c", IAC, DONT, 0377&c);
  2593. X                (void) fflush(stdout);
  2594. X                continue;
  2595. X            case DO:
  2596. X            case DONT:
  2597. X                c = getc(iop);
  2598. X                printf("%c%c%c", IAC, WONT, 0377&c);
  2599. X                (void) fflush(stdout);
  2600. X                continue;
  2601. X            case IAC:
  2602. X                break;
  2603. X            default:
  2604. X                continue;    /* ignore command */
  2605. X            }
  2606. X            }
  2607. X        }
  2608. X        *cs++ = c;
  2609. X        if (--n <= 0 || c == '\n')
  2610. X            break;
  2611. X    }
  2612. X    if (c == EOF && cs == s)
  2613. X        return (NULL);
  2614. X    *cs++ = '\0';
  2615. X    if (debug)
  2616. X        syslog(LOG_DEBUG, "command: %s", s);
  2617. X    return (s);
  2618. X}
  2619. X
  2620. Xstatic int
  2621. Xtoolong()
  2622. X{
  2623. X    time_t now;
  2624. X    extern char *ctime();
  2625. X    extern time_t time();
  2626. X
  2627. X    reply(421,
  2628. X      "Timeout (%d seconds): closing control connection.", timeout);
  2629. X    (void) time(&now);
  2630. X    if (logging) {
  2631. X        syslog(LOG_INFO,
  2632. X            "User %s timed out after %d seconds at %s",
  2633. X            (pw ? pw -> pw_name : "unknown"), timeout, ctime(&now));
  2634. X    }
  2635. X    dologout(1);
  2636. X}
  2637. X
  2638. Xyylex()
  2639. X{
  2640. X    static int cpos, state;
  2641. X    register char *cp, *cp2;
  2642. X    register struct tab *p;
  2643. X    int n;
  2644. X    char c, *strpbrk();
  2645. X    char *copy();
  2646. X
  2647. X    for (;;) {
  2648. X        switch (state) {
  2649. X
  2650. X        case CMD:
  2651. X            (void) signal(SIGALRM, toolong);
  2652. X            (void) alarm((unsigned) timeout);
  2653. X            if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) {
  2654. X                reply(221, "You could at least say goodbye.");
  2655. X                dologout(0);
  2656. X            }
  2657. X            (void) alarm(0);
  2658. X#ifdef SETPROCTITLE
  2659. X            if (strncasecmp(cbuf, "PASS", 4) != NULL)
  2660. X                setproctitle("%s: %s", proctitle, cbuf);
  2661. X#endif /* SETPROCTITLE */
  2662. X            if ((cp = index(cbuf, '\r'))) {
  2663. X                *cp++ = '\n';
  2664. X                *cp = '\0';
  2665. X            }
  2666. X            if ((cp = strpbrk(cbuf, " \n")))
  2667. X                cpos = cp - cbuf;
  2668. X            if (cpos == 0)
  2669. X                cpos = 4;
  2670. X            c = cbuf[cpos];
  2671. X            cbuf[cpos] = '\0';
  2672. X            upper(cbuf);
  2673. X            p = lookup(cmdtab, cbuf);
  2674. X            cbuf[cpos] = c;
  2675. X            if (p != 0) {
  2676. X                if (p->implemented == 0) {
  2677. X                    nack(p->name);
  2678. X                    longjmp(errcatch,0);
  2679. X                    /* NOTREACHED */
  2680. X                }
  2681. X                state = p->state;
  2682. X                *(char **)&yylval = p->name;
  2683. X                return (p->token);
  2684. X            }
  2685. X            break;
  2686. X
  2687. X        case SITECMD:
  2688. X            if (cbuf[cpos] == ' ') {
  2689. X                cpos++;
  2690. X                return (SP);
  2691. X            }
  2692. X            cp = &cbuf[cpos];
  2693. X            if ((cp2 = strpbrk(cp, " \n")))
  2694. X                cpos = cp2 - cbuf;
  2695. X            c = cbuf[cpos];
  2696. X            cbuf[cpos] = '\0';
  2697. X            upper(cp);
  2698. X            p = lookup(sitetab, cp);
  2699. X            cbuf[cpos] = c;
  2700. X            if (p != 0) {
  2701. X                if (p->implemented == 0) {
  2702. X                    state = CMD;
  2703. X                    nack(p->name);
  2704. X                    longjmp(errcatch,0);
  2705. X                    /* NOTREACHED */
  2706. X                }
  2707. X                state = p->state;
  2708. X                *(char **)&yylval = p->name;
  2709. X                return (p->token);
  2710. X            }
  2711. X            state = CMD;
  2712. X            break;
  2713. X
  2714. X        case OSTR:
  2715. X            if (cbuf[cpos] == '\n') {
  2716. X                state = CMD;
  2717. X                return (CRLF);
  2718. X            }
  2719. X            /* FALLTHROUGH */
  2720. X
  2721. X        case STR1:
  2722. X        case ZSTR1:
  2723. X        dostr1:
  2724. X            if (cbuf[cpos] == ' ') {
  2725. X                cpos++;
  2726. X                state = state == OSTR ? STR2 : ++state;
  2727. X                return (SP);
  2728. X            }
  2729. X            break;
  2730. X
  2731. X        case ZSTR2:
  2732. X            if (cbuf[cpos] == '\n') {
  2733. X                state = CMD;
  2734. X                return (CRLF);
  2735. X            }
  2736. X            /* FALLTHROUGH */
  2737. X
  2738. X        case STR2:
  2739. X            cp = &cbuf[cpos];
  2740. X            n = strlen(cp);
  2741. X            cpos += n - 1;
  2742. X            /*
  2743. X             * Make sure the string is nonempty and \n terminated.
  2744. X             */
  2745. X            if (n > 1 && cbuf[cpos] == '\n') {
  2746. X                cbuf[cpos] = '\0';
  2747. X                *(char **)&yylval = copy(cp);
  2748. X                cbuf[cpos] = '\n';
  2749. X                state = ARGS;
  2750. X                return (STRING);
  2751. X            }
  2752. X            break;
  2753. X
  2754. X        case NSTR:
  2755. X            if (cbuf[cpos] == ' ') {
  2756. X                cpos++;
  2757. X                return (SP);
  2758. X            }
  2759. X            if (isdigit(cbuf[cpos])) {
  2760. X                cp = &cbuf[cpos];
  2761. X                while (isdigit(cbuf[++cpos]))
  2762. X                    ;
  2763. X                c = cbuf[cpos];
  2764. X                cbuf[cpos] = '\0';
  2765. X                yylval = atoi(cp);
  2766. X                cbuf[cpos] = c;
  2767. X                state = STR1;
  2768. X                return (NUMBER);
  2769. X            }
  2770. X            state = STR1;
  2771. X            goto dostr1;
  2772. X
  2773. X        case ARGS:
  2774. X            if (isdigit(cbuf[cpos])) {
  2775. X                cp = &cbuf[cpos];
  2776. X                while (isdigit(cbuf[++cpos]))
  2777. X                    ;
  2778. X                c = cbuf[cpos];
  2779. X                cbuf[cpos] = '\0';
  2780. X                yylval = atoi(cp);
  2781. X                cbuf[cpos] = c;
  2782. X                return (NUMBER);
  2783. X            }
  2784. X            switch (cbuf[cpos++]) {
  2785. X
  2786. X            case '\n':
  2787. X                state = CMD;
  2788. X                return (CRLF);
  2789. X
  2790. X            case ' ':
  2791. X                return (SP);
  2792. X
  2793. X            case ',':
  2794. X                return (COMMA);
  2795. X
  2796. X            case 'A':
  2797. X            case 'a':
  2798. X                return (A);
  2799. X
  2800. X            case 'B':
  2801. X            case 'b':
  2802. X                return (B);
  2803. X
  2804. X            case 'C':
  2805. X            case 'c':
  2806. X                return (C);
  2807. X
  2808. X            case 'E':
  2809. X            case 'e':
  2810. X                return (E);
  2811. X
  2812. X            case 'F':
  2813. X            case 'f':
  2814. X                return (F);
  2815. X
  2816. X            case 'I':
  2817. X            case 'i':
  2818. X                return (I);
  2819. X
  2820. X            case 'L':
  2821. X            case 'l':
  2822. X                return (L);
  2823. X
  2824. X            case 'N':
  2825. X            case 'n':
  2826. X                return (N);
  2827. X
  2828. X            case 'P':
  2829. X            case 'p':
  2830. X                return (P);
  2831. X
  2832. X            case 'R':
  2833. X            case 'r':
  2834. X                return (R);
  2835. X
  2836. X            case 'S':
  2837. X            case 's':
  2838. X                return (S);
  2839. X
  2840. X            case 'T':
  2841. X            case 't':
  2842. X                return (T);
  2843. X
  2844. X            }
  2845. X            break;
  2846. X
  2847. X        default:
  2848. X            fatal("Unknown state in scanner.");
  2849. X        }
  2850. X        yyerror((char *) 0);
  2851. X        state = CMD;
  2852. X        longjmp(errcatch,0);
  2853. X    }
  2854. X}
  2855. X
  2856. Xupper(s)
  2857. X    register char *s;
  2858. X{
  2859. X    while (*s != '\0') {
  2860. X        if (islower(*s))
  2861. X            *s = toupper(*s);
  2862. X        s++;
  2863. X    }
  2864. X}
  2865. X
  2866. Xchar *
  2867. Xcopy(s)
  2868. X    char *s;
  2869. X{
  2870. X    char *p;
  2871. X    extern char *malloc(), *strcpy();
  2872. X
  2873. X    p = malloc((unsigned) strlen(s) + 1);
  2874. X    if (p == NULL)
  2875. X        fatal("Ran out of memory.");
  2876. X    (void) strcpy(p, s);
  2877. X    return (p);
  2878. X}
  2879. X
  2880. Xhelp(ctab, s)
  2881. X    struct tab *ctab;
  2882. X    char *s;
  2883. X{
  2884. X    register struct tab *c;
  2885. X    register int width, NCMDS;
  2886. X    char *type;
  2887. X
  2888. X    if (ctab == sitetab)
  2889. X        type = "SITE ";
  2890. X    else
  2891. X        type = "";
  2892. X    width = 0, NCMDS = 0;
  2893. X    for (c = ctab; c->name != NULL; c++) {
  2894. X        int len = strlen(c->name);
  2895. X
  2896. X        if (len > width)
  2897. X            width = len;
  2898. X        NCMDS++;
  2899. X    }
  2900. X    width = (width + 8) &~ 7;
  2901. X    if (s == 0) {
  2902. X        register int i, j, w;
  2903. X        int columns, lines;
  2904. X
  2905. X        lreply(214, "The following %scommands are recognized %s.",
  2906. X            type, "(* =>'s unimplemented)");
  2907. X        columns = 76 / width;
  2908. X        if (columns == 0)
  2909. X            columns = 1;
  2910. X        lines = (NCMDS + columns - 1) / columns;
  2911. X        for (i = 0; i < lines; i++) {
  2912. X            printf("   ");
  2913. X            for (j = 0; j < columns; j++) {
  2914. X                c = ctab + j * lines + i;
  2915. X                printf("%s%c", c->name,
  2916. X                    c->implemented ? ' ' : '*');
  2917. X                if (c + lines >= &ctab[NCMDS])
  2918. X                    break;
  2919. X                w = strlen(c->name) + 1;
  2920. X                while (w < width) {
  2921. X                    putchar(' ');
  2922. X                    w++;
  2923. X                }
  2924. X            }
  2925. X            printf("\r\n");
  2926. X        }
  2927. X        (void) fflush(stdout);
  2928. X        reply(214, "Direct comments to ftp-bugs@%s.", hostname);
  2929. X        return;
  2930. X    }
  2931. X    upper(s);
  2932. X    c = lookup(ctab, s);
  2933. X    if (c == (struct tab *)0) {
  2934. X        reply(502, "Unknown command %s.", s);
  2935. X        return;
  2936. X    }
  2937. X    if (c->implemented)
  2938. X        reply(214, "Syntax: %s%s %s", type, c->name, c->help);
  2939. X    else
  2940. X        reply(214, "%s%-*s\t%s; unimplemented.", type, width,
  2941. X            c->name, c->help);
  2942. X}
  2943. X
  2944. Xsizecmd(filename)
  2945. Xchar *filename;
  2946. X{
  2947. X    switch (type) {
  2948. X    case TYPE_L:
  2949. X    case TYPE_I: {
  2950. X        struct stat stbuf;
  2951. X        if (stat(filename, &stbuf) < 0 ||
  2952. X            (stbuf.st_mode&S_IFMT) != S_IFREG)
  2953. X            reply(550, "%s: not a plain file.", filename);
  2954. X        else
  2955. X            reply(213, "%lu", stbuf.st_size);
  2956. X        break;}
  2957. X    case TYPE_A: {
  2958. X        FILE *fin;
  2959. X        register int c, count;
  2960. X        struct stat stbuf;
  2961. X        fin = fopen(filename, "r");
  2962. X        if (fin == NULL) {
  2963. X            perror_reply(550, filename);
  2964. X            return;
  2965. X        }
  2966. X        if (fstat(fileno(fin), &stbuf) < 0 ||
  2967. X            (stbuf.st_mode&S_IFMT) != S_IFREG) {
  2968. X            reply(550, "%s: not a plain file.", filename);
  2969. X            (void) fclose(fin);
  2970. X            return;
  2971. X        }
  2972. X
  2973. X        count = 0;
  2974. X        while((c=getc(fin)) != EOF) {
  2975. X            if (c == '\n')    /* will get expanded to \r\n */
  2976. X                count++;
  2977. X            count++;
  2978. X        }
  2979. X        (void) fclose(fin);
  2980. X
  2981. X        reply(213, "%ld", count);
  2982. X        break;}
  2983. X    default:
  2984. X        reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]);
  2985. X    }
  2986. X}
  2987. END_OF_FILE
  2988. if test 22998 -ne `wc -c <'test/ftp.y'`; then
  2989.     echo shar: \"'test/ftp.y'\" unpacked with wrong size!
  2990. fi
  2991. # end of 'test/ftp.y'
  2992. fi
  2993. echo shar: End of archive 4 \(of 5\).
  2994. cp /dev/null ark4isdone
  2995. MISSING=""
  2996. for I in 1 2 3 4 5 ; do
  2997.     if test ! -f ark${I}isdone ; then
  2998.     MISSING="${MISSING} ${I}"
  2999.     fi
  3000. done
  3001. if test "${MISSING}" = "" ; then
  3002.     echo You have unpacked all 5 archives.
  3003.     rm -f ark[1-9]isdone
  3004. else
  3005.     echo You still need to unpack the following archives:
  3006.     echo "        " ${MISSING}
  3007. fi
  3008. ##  End of shell archive.
  3009. exit 0
  3010.